%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drbdadm_parser.h"
#include "drbdadm.h"

void long_string(char* text);
void long_dqstring(char* text);
void err_dqstring(char* text);
static void unescape(void);

#if 0
#define DP printf("'%s' ",yytext)
#else
#define DP
#endif

#define CP yylval.txt = strdup(yytext); yylval.rc = R_NO_CHECK
#define RC(N) yylval.rc = R_ ## N

#define YY_NO_UNPUT 1
static void yyunput (int c, register char * yy_bp ) __attribute((unused));

%}

%option noyywrap

NUM		[0-9]{1,8}[MKGs]?
SNUMB		[0-9]{1,3}
IPV4ADDR	({SNUMB}"."){3}{SNUMB}
WS		[ \t\r]
OPCHAR		[{};\[\]:]
DQSTRING	\"([^\"\\\n]|\\[^\n]){0,255}\"
LONG_DQSTRING	\"([^\"\\\n]|\\[^\n]){255}.
ERR_DQSTRING	\"([^\"\\\n]|\\[^\n]){0,255}[\\\n]
STRING		[a-zA-Z0-9/._-]{1,80}
LONG_STRING	[a-zA-Z0-9/._-]{81}

%%

\n			{ line++; 				}
\#.*			/* ignore comments */
{WS}			/* ignore whitespaces */
{OPCHAR}		{ DP; return yytext[0];			}
on			{ DP; return TK_ON;			}
no			{ DP; return TK_NO;			}
net			{ DP; return TK_NET;			}
yes			{ DP; return TK_YES;			}
ask			{ DP; return TK_ASK;			}
skip			{ DP; return TK_SKIP;			}
disk			{ DP; return TK_DISK;			}
syncer			{ DP; return TK_SYNCER;			}
device			{ DP; return TK_DEVICE;			}
global			{ DP; return TK_GLOBAL;			}
common			{ DP; return TK_COMMON;			}
address			{ DP; return TK_ADDRESS;		}
startup			{ DP; return TK_STARTUP;		}
handlers		{ DP; return TK_HANDLER;		}
protocol		{ DP; return TK_PROTOCOL;		}
minor-count		{ DP; return TK_MINOR_COUNT;		}
disable-ip-verification { DP; return TK_DISABLE_IP_VERIFICATION;}
dialog-refresh		{ DP; return TK_DIALOG_REFRESH;		}
resource		{ DP; return TK_RESOURCE;		}
meta-disk		{ DP; return TK_META_DISK;		}
flexible-meta-disk	{ DP; return TK_FLEX_META_DISK;		}
usage-count 		{ DP; return TK_USAGE_COUNT;		}
_is_default 		{ DP; return TK__IS_DEFAULT;		}
_this_host 		{ DP; return TK__THIS_HOST;		}
_remote_host 		{ DP; return TK__REMOTE_HOST;		}
size			{ DP; CP; RC(DISK_SIZE); return TK_DISK_OPTION;	}
on-io-error		{ DP; CP; return TK_DISK_OPTION;	}
fencing			{ DP; CP; return TK_DISK_OPTION;	}
use-bmbv		{ DP; CP; return TK_DISK_SWITCH;		}
no-disk-flushes		{ DP; CP; return TK_DISK_SWITCH;		}
no-md-flushes		{ DP; CP; return TK_DISK_SWITCH;		}
timeout			{ DP; CP; RC(TIMEOUT); return TK_NET_OPTION;	}
ko-count		{ DP; CP; RC(KO_COUNT); return TK_NET_OPTION;	}
ping-int		{ DP; CP; RC(PING_INT); return TK_NET_OPTION;	}
max-buffers		{ DP; CP; RC(MAX_BUFFERS); return TK_NET_OPTION;}
sndbuf-size		{ DP; CP; RC(SNDBUF_SIZE); return TK_NET_OPTION;}
connect-int		{ DP; CP; RC(CONNECT_INT); return TK_NET_OPTION;}
cram-hmac-alg		{ DP; CP; return TK_NET_OPTION;		}
shared-secret		{ DP; CP; return TK_NET_OPTION;		}
max-epoch-size		{ DP; CP; RC(MAX_EPOCH_SIZE); return TK_NET_OPTION;}
after-sb-[012]pri	{ DP; CP; return TK_NET_OPTION;		}
rr-conflict 		{ DP; CP; return TK_NET_OPTION;		}
ping-timeout 		{ DP; CP; return TK_NET_OPTION;		}
unplug-watermark	{ DP; CP; return TK_NET_OPTION;         }
allow-two-primaries	{ DP; CP; return TK_NET_SWITCH;		}
always-asbp		{ DP; CP; return TK_NET_SWITCH;		}
discard-my-data		{ DP; CP; return TK_NET_DELEGATE;	}
rate			{ DP; CP; RC(RATE); return TK_SYNCER_OPTION;	}
after			{ DP; CP; return TK_SYNCER_OPTION;	}
al-extents		{ DP; CP; RC(AL_EXTENTS); return TK_SYNCER_OPTION;}
wfc-timeout		{ DP; CP; RC(WFC_TIMEOUT); return TK_STARTUP_OPTION;}
degr-wfc-timeout	{ DP; CP; RC(DEGR_WFC_TIMEOUT); return TK_STARTUP_OPTION;}
become-primary-on	{ DP; CP; return TK_STARTUP_OPTION;     }
wait-after-sb		{ DP; CP; return TK_STARTUP_SWITCH;     }
pri-on-incon-degr	{ DP; CP; return TK_HANDLER_OPTION;	}
pri-lost-after-sb	{ DP; CP; return TK_HANDLER_OPTION;	}
pri-lost		{ DP; CP; return TK_HANDLER_OPTION;     }
split-brain		{ DP; CP; return TK_HANDLER_OPTION;     }
outdate-peer		{ DP; CP; return TK_HANDLER_OPTION;	}
local-io-error		{ DP; CP; return TK_HANDLER_OPTION;     }
{IPV4ADDR}		{ DP; CP; return TK_IPADDR;		}
{NUM}			{ DP; CP; return TK_INTEGER;		}
{DQSTRING}		{ unescape(); DP; CP; return TK_STRING;	}
{STRING}		{ DP; CP; return TK_STRING;		}
{LONG_STRING}		{ return TK_ERR_STRING_TOO_LONG;	}
{LONG_DQSTRING}		{ return TK_ERR_DQSTRING_TOO_LONG;	}
{ERR_DQSTRING}		{ return TK_ERR_DQSTRING;		}
.			{ DP; return TK_ELSE;			}

%%


static void unescape(void)
{
  /* backslash escapes from string */
  char *ue, *e;
  e = ue = yytext;
  for (;;) {
    if (*ue == '"')
      ue++;
    if (*ue == '\\')
      ue++;
    if (!*ue)
      break;
    *e++ = *ue++;
  }
  *e = '\0';
}
