/*
//  $Id: rpsl.l,v 1.3 2000/11/27 17:56:33 engin Exp $
//
//  Copyright (c) 1994 by the University of Southern California
//  All rights reserved.
//
//  Permission to use, copy, modify, and distribute this software and its
//  documentation in source and binary forms for lawful non-commercial
//  purposes and without fee is hereby granted, provided that the above
//  copyright notice appear in all copies and that both the copyright
//  notice and this permission notice appear in supporting documentation,
//  and that any documentation, advertising materials, and other materials
//  related to such distribution and use acknowledge that the software was
//  developed by the University of Southern California, Information
//  Sciences Institute. The name of the USC may not be used to endorse or
//  promote products derived from this software without specific prior
//  written permission.
//
//  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY
//  REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY
//  PURPOSE.  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
//  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
//  TITLE, AND NON-INFRINGEMENT.
//
//  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
//  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT,
//  OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE
//  OR PERFORMANCE OF THIS SOFTWARE.
//
//  Questions concerning this software should be directed to
//  ratoolset@isi.edu.
//
//  Author(s): Cengiz Alaettinoglu <cengiz@ISI.EDU>
*/

/* definitions */
%x STRING
%x EXPECT_OPERATOR
%x FREETEXT
%x BLOBMODE
%x GENERICMODE
%x SKIP_OBJECT
%x POLICYMODE

/*%option nodefault /* */
/*%option debug     /* */
%option case-insensitive

ENDOBJECT      ^[ \t\r]*\n
WS             [ \t\r]
NWS            [^ \t\r\n]
INT            [[:digit:]]+
SINT           [+-]?{INT}
REAL           [+-]?{INT}?\.{INT}({WS}*E{WS}*[+-]?{INT})?
NAME           [[:alpha:]]([[:alnum:]_-]*[[:alnum:]])?
ASNO           AS{INT}
ASNAME         AS-[[:alnum:]_-]*[[:alnum:]]
RSNAME         RS-[[:alnum:]_-]*[[:alnum:]]
RTRSNAME       RTRS-[[:alnum:]_-]*[[:alnum:]]
PRNGNAME       PRNG-[[:alnum:]_-]*[[:alnum:]]
FLTRNAME       FLTR-[[:alnum:]_-]*[[:alnum:]]
KEYCRTNAME     PGPKEY-[[:xdigit:]]{8}
IPV4           [0-9]+(\.[0-9]+){3,3}
QUAD           [[:xdigit:]]{1,4}
IPV6           {QUAD}(:{QUAD}){7,7}
IPV6DC         ({QUAD}(:{QUAD}){0,6})?::({QUAD}(:{QUAD}){0,6})?
INT128         [[:digit:]]{1,2}|1[01][[:digit:]]|12[0-8]
PRFXV6         ({IPV6}|{IPV6DC}\/INT128
PRFXV4         {IPV4}\/[0-9]+
PRFXV4RNG      {PRFXV4}("^+"|"^-"|"^"{INT}|"^"{INT}-{INT})
ENAMECHAR      [^()<>,;:\\\"\.[\] \t\r]
ENAME          ({ENAMECHAR}+(\.{ENAMECHAR}+)*\.?)|(\"[^\"@\\\r\n]+\")
DNAME          [[:alnum:]_-]+
EMAIL          {ENAME}@({DNAME}("."{DNAME})+|{IPV4})
YYYYMMDD       [0-9]{8,8}
HHMMSS         [0-9][0-9]:[0-9][0-9]:[0-9][0-9]
HHMM           [0-9][0-9]:[0-9][0-9]
NICHDL         [[:alpha:]]{2,4}([[:digit:]][[:digit:]]{0,5})?([a-zA-Z\-_]+)?|AUTO-[[:digit:]]+([[:alpha:]]{2,4})?
CRYPTPW        [[:alnum:]\./]{13}

%{
#include "config.h"
#include <cstring>
#include <cstdarg>
#include <cstdio>
#include <time.h>

#include "object.hh"
#include "rpsl.y.hh"
#include "schema.hh"

static int errorLine = 0;
static int errorColon = 0;
#define errorNewLine { errorLine++;   errorColon = 0; }

static int scan_position = 0;
static bool start_of_object = true;
static bool genericMode = true;
static int oldStart = 0;

Object *current_object;
Attr   *current_attribute;
YY_BUFFER_STATE rpsl_buffer = (YY_BUFFER_STATE) NULL;

#define MAX_STR_CONST 1024
#define LEXER_RETURN return
#define YY_USER_ACTION { scan_position += yyleng; errorColon += yyleng; }
#define YYLESS(n) {scan_position -= yyleng - n; errorColon -= yyleng - n; yyless(n); }
#define yylval rpsllval
#define yy_scan_object rpsl_scan_object
#define yyschema schema

extern void handle_error(char *, ...);
extern void handle_warning(char *, ...);
extern int validIPv6(const char *);
extern int validIntForPhone(const char *);

extern "C" {
extern void atollRA(...);
}
%}

%%
%{ 
   /* this code is copied to beginning of yylex */
   static char string_buf[MAX_STR_CONST];
   char *string_buf_ptr;
%}

^{NAME}: { //
   errorLine = 0; 
   errorColon = yyleng;

   *(yytext + yyleng - 1) = 0; // remove ':'

   yylval.attr = new Attr;
   yylval.attr->offset = scan_position - yyleng;
   current_attribute = yylval.attr;

   if (start_of_object) {
      start_of_object = false;
      current_object->type = yyschema.searchClass(yytext);
      if (!current_object->type) {
	 handle_error("Error: unknown class \"%s\"\n", yytext);
	 yylval.attr->type   = NULL;
//(*current_object) += yylval.attr;
	 BEGIN(SKIP_OBJECT);
	 LEXER_RETURN(TKN_UNKNOWN_CLASS);
      }
   }

   yylval.attr->type   = current_object->type->searchAttr(yytext);
   yylval.attr->object = current_object;

//   (*current_object) += yylval.attr;

   if (! yylval.attr->type) {
      if (! schema.isForgiving())
	 handle_error("Error: unknown attribute %s of class %s\n",
		      yytext, current_object->type->name);
      BEGIN(FREETEXT);
      LEXER_RETURN(ATTR_FREETEXT);
   }

   if (yylval.attr->type->isObsolete())
      handle_warning("Warning: attribute %s of class %s is now obsolete\n", 
	      yytext, current_object->type->name);

   if (!yylval.attr->type->shouldParse()) { // may be free text?
      BEGIN(FREETEXT);
      LEXER_RETURN(ATTR_FREETEXT);
   } else {
      if (yylval.attr->type->syntax() == ATTR_GENERIC) {
	 genericMode = true;
	 BEGIN(GENERICMODE);
      } else if (yylval.attr->type->syntax() == ATTR_BLOBS) {
	 genericMode = true;
	 BEGIN(BLOBMODE);
      } else {
	 genericMode = false;
	 BEGIN(POLICYMODE);
      }
      LEXER_RETURN(yylval.attr->type->syntax());
   }
}

{ENDOBJECT}  {
   if (current_attribute)
      current_attribute->len = scan_position - current_attribute->offset;
   LEXER_RETURN(TKN_EOO);
}

<<EOF>> {
   yy_delete_buffer(rpsl_buffer);
   rpsl_buffer = (YY_BUFFER_STATE) NULL;
   if (current_attribute)
      current_attribute->len = scan_position - current_attribute->offset;
   BEGIN(INITIAL);
   yyterminate();
}

#.*

. { // not a valid line
   current_attribute = NULL;
   handle_error("Error: valid lines start with attribute names, spaces or #\n");
   BEGIN(FREETEXT);
   LEXER_RETURN(TKN_ERROR);
}

<SKIP_OBJECT>{
  {ENDOBJECT} {
     BEGIN(INITIAL);
     if (current_attribute)
        current_attribute->len = scan_position - current_attribute->offset;
     LEXER_RETURN(TKN_EOO);
  }
  \n          errorNewLine;
  .+          ;
}

<FREETEXT,BLOBMODE,GENERICMODE,POLICYMODE,EXPECT_OPERATOR>{
   \n\+             errorNewLine; errorColon++; // line continuation with +
   \n/[ \t\r#]      errorNewLine; // line continuation with space or comment
   \n/([ \t\r]+\n)? { // end of attribute and may be end of object too
      BEGIN(INITIAL);
      if (current_attribute)
	 current_attribute->len = scan_position - current_attribute->offset;
      LEXER_RETURN(TKN_EOA);
   }
   {WS}+            ; // skip white space
   #.*              ; // skip comment 
}

<FREETEXT>{     // dont parse anything, keep going till EOA
  .+          ; // this rule needs to be after \n rules
}

<BLOBMODE>{
  {NWS}+      {
     yylval.string = strdup(yytext);
     LEXER_RETURN(TKN_BLOB);
  }
}

<GENERICMODE>{
  {YYYYMMDD}{WS}+{HHMMSS}{WS}+[-+]{HHMM} {
     tm ts;
     bzero((char *) &ts, sizeof(ts));

     int date, zone_hours, zone_mins;
     sscanf(yytext, "%d %d:%d:%d %d:%d", 
		    &date, 
		    &ts.tm_hour, &ts.tm_min, &ts.tm_sec,
		    &zone_hours, &zone_mins);

     ts.tm_mday = date % 100; date /= 100;
     ts.tm_mon  = date % 100 - 1; date /= 100;
     ts.tm_year = date - 1900;
   
     if (ts.tm_mday > 31) {
	handle_error("Error: Invalid day %d\n", ts.tm_mday);
	LEXER_RETURN(TKN_ERROR);
     }
     if (ts.tm_mon > 11) {
	handle_error("Error: Invalid month %d\n", ts.tm_mon);
	LEXER_RETURN(TKN_ERROR);
     }
     if (ts.tm_year < 70) {
	handle_error("Error: Invalid year %d\n", ts.tm_year);
	LEXER_RETURN(TKN_ERROR);
     }
     if (ts.tm_sec > 59) {
	handle_error("Error: Invalid sec %d\n", ts.tm_sec);
	LEXER_RETURN(TKN_ERROR);
     }
     if (ts.tm_min > 59) {
	handle_error("Error: Invalid min %d\n", ts.tm_min);
	LEXER_RETURN(TKN_ERROR);
     }
     if (ts.tm_hour > 23) {
	handle_error("Error: Invalid hour %d\n", ts.tm_hour);
	LEXER_RETURN(TKN_ERROR);
     }
     if (zone_mins > 59) {
	handle_error("Error: Invalid zone min %d\n", zone_mins);
	LEXER_RETURN(TKN_ERROR);
     }
     if (zone_hours > 23) {
	handle_error("Error: Invalid zone hour %d\n", zone_hours);
	LEXER_RETURN(TKN_ERROR);
     }

     // this fiddling with TZ is necessary for mktime to use utc as timezone
     // it sucks, there's got to be a better way
     time_t result = mktime(&ts);
     result -= timezone;
/*
     char *TZ=getenv("TZ");
     if (TZ)
	TZ = strdup(TZ);
     setenv("TZ", "", 1);
     time_t result = mktime(&ts);
     if (TZ) {
	setenv("TZ", TZ, 1);
	free(TZ);
     } else
	unsetenv("TZ");
*/
     if (zone_hours < 0)
	zone_mins *= -1;

     result += zone_mins * 60 + zone_hours * 60 * 60;
   
     yylval.time = result;
     LEXER_RETURN(TKN_TIMESTAMP);
  }
}

<GENERICMODE,POLICYMODE>{
  
    {CRYPTPW} {
     if(current_attribute->type->syntax() == ATTR_AUTH){
     yylval.string = strdup(yytext);
     LEXER_RETURN(TKN_CRYPTEDPW);
     }else{
       scan_position -= yyleng; errorColon -= yyleng;
       REJECT;
     }
  }
  
    {SINT} {
     // The following code causes problem on Solaris since long long int
     // is not standardized yet 
     // sscanf(yytext, "%Ld", &(yylval.i));
     if(current_attribute->type->syntax() == ATTR_PHONE){
       if(validIntForPhone(yytext)){
         atollRA(yytext, &yylval.i);
         LEXER_RETURN(TKN_INT);
       }else{
         scan_position -= yyleng; errorColon -= yyleng;
         REJECT;
       }
     }else{
       atollRA(yytext, &yylval.i);
       LEXER_RETURN(TKN_INT);
     }
    /* atollRA(yytext, &yylval.i);
     LEXER_RETURN(TKN_INT);*/
  }

  {INT}:{INT} {
     unsigned int ms, ls;
     char *colon = strchr(yytext, ':');
     *colon = 0;
     ms = atoi(yytext);
     ls = atoi(colon+1);
     if (ms > 65535 || ls > 65535)
	LEXER_RETURN(TKN_ERROR);

     yylval.i = (ms << 16) + ls;
     LEXER_RETURN(TKN_INT);
  }

  {REAL} {
     yylval.real = atof(yytext);
     LEXER_RETURN(TKN_REAL);
  }

  \"  {
     string_buf_ptr = string_buf; 
     oldStart = YY_START;
     BEGIN(STRING);
  }

  {IPV4}    {
     yylval.ip = new IPAddr(yytext);
     LEXER_RETURN(TKN_IPV4);
  }

  {IPV6}\/{INT128}    {
     yylval.string = strdup(yytext);
     printf("debug: lexer: Returning TKN_PRFXV6\n");
     LEXER_RETURN(TKN_PRFXV6);
  }

  {IPV6DC}\/{INT128}    {
     yylval.string = strdup(yytext);
     if(validIPv6(yylval.string)){
        printf("debug: lexer: Returning TKN_PRFXV6\n");
        LEXER_RETURN(TKN_PRFXV6);
     }else{
        handle_error("Error: Invalid IPv6 prefix\n");
        BEGIN(FREETEXT);
        LEXER_RETURN(TKN_ERROR);
     }
  }

  {PRFXV4}  {
     yylval.prfx = new Prefix(yytext);
     LEXER_RETURN(TKN_PRFXV4);
  }

  {PRFXV4RNG}  {
     yylval.prfxrng = new PrefixRange(yytext);
     LEXER_RETURN(TKN_PRFXV4RNG);
  }

  {NICHDL} {
      /*printf("DEBUG: lexer: matched a nichdl candidate (%s)\n",yytext);*/
      if(current_attribute->type->syntax() != ATTR_NICHDL){
        /*printf("DEBUG: lexer: This is not a nichdl attribute, rejecting\n");*/
        scan_position -= yyleng; errorColon -= yyleng;
        REJECT;
      }else{
        yylval.string = strdup(yytext);
        LEXER_RETURN(TKN_NICHDL);
      }
  }


  /* The order of these rules are important */
  {ASNO} {
     yylval.i = atoi(yytext+2);
     LEXER_RETURN(TKN_ASNO);
  }

  (({ASNO}|peeras|{ASNAME}):)*{ASNAME}(:({ASNO}|peeras|{ASNAME}))* {
     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_ASNAME);
  }

  (({ASNO}|peeras|{RSNAME}):)*{RSNAME}(:({ASNO}|peeras|{RSNAME}))*  {
     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_RSNAME);
  }

  (({ASNO}|peeras|{RTRSNAME}):)*{RTRSNAME}(:({ASNO}|peeras|{RTRSNAME}))*  {
     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_RTRSNAME);
  }

  (({ASNO}|peeras|{PRNGNAME}):)*{PRNGNAME}(:({ASNO}|peeras|{PRNGNAME}))*  {
     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_PRNGNAME);
  }

  (({ASNO}|peeras|{FLTRNAME}):)*{FLTRNAME}(:({ASNO}|peeras|{FLTRNAME}))*  {
     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_FLTRNAME);
  }

  true {
     yylval.i = 1;
     LEXER_RETURN(TKN_BOOLEAN);
  }

  false {
     yylval.i = 0;
     LEXER_RETURN(TKN_BOOLEAN);
  }

  {KEYCRTNAME} { /* keycert name */  
     yylval.string = strdup(yytext);
     LEXER_RETURN(TKN_KEYCRTNAME);
  }


 {NAME} { /* reserved word or rp-attribute, or arbitrary name */
     if (!genericMode) {
	oldStart = YY_START;

	int index;
	if ((index  = yyschema.searchKeyword(yytext)) >= 0) {
	   if (index == KEYW_OPERATOR)
	      BEGIN(EXPECT_OPERATOR);
	   LEXER_RETURN(index);
	}
     
	if ((yylval.rp_attr = yyschema.searchRPAttr(yytext)) != NULL) {
	   BEGIN(EXPECT_OPERATOR);
	   LEXER_RETURN(TKN_RP_ATTR);
	}
     }

     yylval.string = strdup(yytext);
     LEXER_RETURN(TKN_WORD);
  }

  {NAME}"."{NAME}  { /* rp-attribute.method or DNS name */
     if (!genericMode) {
	char *p = strchr(yytext, '.');
	*p = 0;

	if ((yylval.rp_attr = yyschema.searchRPAttr(yytext)) != NULL) {
	   *p = '.';
	   YYLESS((p - yytext));
	   LEXER_RETURN(TKN_RP_ATTR);
	}

	*p = '.';
     }

     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_DNS);
  }

  {DNAME}("."{DNAME})+ { /* DNS name */
     yylval.sid = symbols.symID(yytext);
     LEXER_RETURN(TKN_DNS);
  }

  {EMAIL} { /* email */  
     yylval.string = strdup(yytext);
     LEXER_RETURN(TKN_EMAIL);
  }



  . {
     if (*yytext <= 0) {
	handle_error("Error: Non-ASCII character encountered\n");
	LEXER_RETURN(TKN_ERROR);
     } else
	LEXER_RETURN(*yytext);
  }
}

<POLICYMODE>{
   \^- {
      yylval.moreSpecOp = new FilterMS(0);
      LEXER_RETURN(OP_MS);
   }

   \^\+ {
      yylval.moreSpecOp = new FilterMS(1);
      LEXER_RETURN(OP_MS);
   }

   \^{INT} {
      int i;
      sscanf(yytext, "^%d", &i);
      yylval.moreSpecOp = new FilterMS(2, i, i);
      LEXER_RETURN(OP_MS);
   }

   \^{INT}-{INT} {
      int i, j;
      sscanf(yytext, "^%d-%d", &i, &j);
      yylval.moreSpecOp = new FilterMS(2, i, j);
      LEXER_RETURN(OP_MS);
   }

   "..." LEXER_RETURN(TKN_3DOTS);
}

<EXPECT_OPERATOR>{
   (("<<"|">>`"|"+"|"-"|"*"|"/"|"."|"="|"!"|"<"|">")?=|"<"|">"|"()"|"[]") {
      yylval.string = strdup(yytext);
      BEGIN(oldStart);
      LEXER_RETURN(TKN_OPERATOR);
   }
   
   . {
      YYLESS(0); 
      BEGIN(oldStart);
   }
}

<STRING>{
   \" { /* saw closing quote - all done */
      BEGIN(oldStart);
      *string_buf_ptr = '\0';
      yylval.string = strdup(string_buf);
      LEXER_RETURN(TKN_STRING);
   }
   
   \n {
      errorNewLine;
      handle_error("Error: unterminated string encountered\n");
      BEGIN(oldStart);
      if (current_attribute)
	 current_attribute->len = scan_position - current_attribute->offset;
      LEXER_RETURN(TKN_EOA);
   }

   \\[0-7]{1,3} {
      /* octal escape sequence */
      int result;
      
      (void) sscanf( yytext + 1, "%o", &result );

      if ( result > 0xff ) {
	 handle_error("Error: octal escape sequence is out of bounds\n");
	 BEGIN(oldStart);
	 LEXER_RETURN(TKN_ERROR);
      }

      *string_buf_ptr++ = result;
   }

   \\[0-9]+ {			/* like '\48' or '\0777777' */
      handle_error("Error: bad octal escape sequence\n");
      BEGIN(oldStart);
      LEXER_RETURN(TKN_ERROR);
   }

   \\n  *string_buf_ptr++ = '\n';
   \\t  *string_buf_ptr++ = '\t';
   \\r  *string_buf_ptr++ = '\r';
   \\b  *string_buf_ptr++ = '\b';
   \\f  *string_buf_ptr++ = '\f';

   \\(.|\n)  *string_buf_ptr++ = yytext[1];
   
   [^\\\n\"]+        {
      char *yptr = yytext;
      while ( *yptr )
	 *string_buf_ptr++ = *yptr++;
   }

   .  *string_buf_ptr++ = yytext[0];
}

%%
extern "C" {
int yywrap () {
   return 1;
}
}

void handle_error(char *s, ...) {
   current_object->has_error = true;

   char buffer[1024] = "***";
   va_list ap;
   va_start(ap, s);
   vsprintf(buffer+3, s, ap);
   va_end(ap);

   if (current_attribute)
      current_attribute->errors += buffer;
   else 
      current_object->errors += buffer;
}

void handle_object_error(char *s, ...) {
   current_object->has_error = true;

   char buffer[1024] = "***";
   va_list ap;
   va_start(ap, s);
   vsprintf(buffer+3, s, ap);
   va_end(ap);

   current_object->errors += buffer;
}

void rpslerror(char *, ...) {
   if (current_attribute) {
      current_attribute->errorLine = errorLine;
      current_attribute->errorColon = errorColon - yyleng;
      current_attribute->errorLeng  = yyleng;
   }
}

void handle_warning(char *s, ...) {
   current_object->has_warning = true;

   char buffer[1024];
   va_list ap;
   va_start(ap, s);
   vsprintf(buffer, s, ap);
   va_end(ap);

   if (current_attribute) 
      current_attribute->errors += buffer;
   else 
      current_object->errors += buffer;
}

void yy_scan_object(Object *o) {
   errorLine = 0; 
   errorColon = 0;
   current_object = o;
   current_attribute = NULL;
   start_of_object = true;
   scan_position = 0;
   genericMode = true;

   if (rpsl_buffer)
      yy_delete_buffer(rpsl_buffer);
   rpsl_buffer = yy_scan_bytes(o->contents, o->size);
   BEGIN(INITIAL);
}

Attr *changeCurrentAttr(Attr *b) {
   if (current_attribute) {
      b->object = current_attribute->object;
      b->type   = current_attribute->type;
      b->offset = current_attribute->offset;;
      b->len    = current_attribute->len;
      b->errors = current_attribute->errors;
      b->errorLine  = current_attribute->errorLine;
      b->errorColon = current_attribute->errorColon;
      b->errorLeng  = current_attribute->errorLeng;
      delete current_attribute;
   }
   current_attribute = b;
   return b;
}

int validIPv6(const char *s){
   char *string, *sleft, *sright, *pos;
   int countleft = 0, countright = 0; 
   string = strdup(s);
   pos = strstr(string,"/");
   pos[0] = '\0';
   sleft = strdup(string);
   pos = strstr(sleft,"::");
   pos[0] = '\0';  
   sright = pos + 2;
   // count the ':'s on the left
   for(int i=0;i<strlen(sleft);i++){
     if(sleft[i] == ':'){ countleft++;} 
   }
   // count the ':'s on the right
   for(int i=0;i<strlen(sright);i++){
     if(sright[i] == ':'){ countright++;} 
   }
   printf("The two parts are: %s and %s\nCounts are %i and %i\n",
                           sleft, sright, countleft, countright); 

   // now, if the total # of quads is  > 8, than there
   // is a problem with the syntax of the ipv6 address.
   if((countleft + 1 + countright + 1) <= 8 ){
     return 1;
   }else{
     return 0;
   }
}

int validIntForPhone(const char * arg){
   /* Checks if the integer is valid  as a phone no (should not contain '+' or '-')*/
   if((strchr(arg,'+') == NULL) && (strchr(arg,'-') == NULL)){
       return 1;
   }
   return 0;
}

