/* ----------------------------------------------------------------------- *
 *
 *  Copyright 2013 Ian Kent <raven@themaw.net>
 *  Copyright 2013 Red Hat, Inc.
 *  All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 *  USA; either version 2 of the License, or (at your option) any later
 *  version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 * ----------------------------------------------------------------------- */

%s START MAPOPTVAL FSOPTVAL MNTOPTVAL SELOPTVAL SELARGVAL

%{

static int reset_start_state = 0;

#ifdef ECHO
# undef ECHO
#endif
static void amd_echo(void);	/* forward definition */
static void amd_copy_buffer(void);
#define ECHO amd_echo()
int amd_wrap(void);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "amd_parse.tab.h"

int amd_lex(void);
int mad_wrap(void);

#define YY_SKIP_YYWRAP

#ifndef YY_STACK_USED
#define YY_STACK_USED 0
#endif
#ifndef YY_ALWAYS_INTERACTIVE
#define YY_ALWAYS_INTERACTIVE 0
#endif
#ifndef YY_NEVER_INTERACTIVE
#define YY_NEVER_INTERACTIVE 0
#endif
#ifndef YY_MAIN
#define YY_MAIN 0
#endif

void amd_set_scan_buffer(const char *);
static const char *line = NULL;

#ifdef FLEX_SCANNER
static const char *line_pos = NULL;
static const char *line_lim = NULL;
int amd_yyinput(char *, int);

#undef YY_INPUT
#define YY_INPUT(b, r, ms) (r = amd_yyinput(b, ms))
#else
#undef input
#undef unput
#define input()  (*(char *) line++)
#define unput(c) (*(char *) --line = c)
#endif

%}

%option nounput

NL		\r?\n
OPTWS		[[:blank:]]*
OTHR		[^!;:=/|\- \t\r\n#]*

V4NUM		([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])

MACRO		(\$\{([[:alpha:]_/]([[:alnum:]_\-])([[:alnum:]_\-/])*)\})
QSTR		(\"([^"\\]|\\.)*\")
OSTR		([[:alpha:]]([[:alnum:]_\-])+)
FSTR		([[:alnum:]_/\.]([[:alnum:]_\-/\+\.]|(\\.))*)
VSTR		(([[:alnum:]_\-\:/\.])+)
SSTR		([[:alpha:]]([[:alnum:]\-\.])+)
IP4ADDR		({V4NUM}\.((({V4NUM}\.){0,2}){V4NUM}?))
V4MASK		({IP4ADDR}|([1-2][0-9]|3[0-2]|[1-9]))
IP6ADDR		((([A-Fa-f0-9]{1,4}\:\:?){1,7}[A-Fa-f0-9]{1,4})|(\:\:1))
V6MASK		(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[1-9])

FOPT		(({QSTR}|{FSTR}|{MACRO})+)
OPTS		({OSTR}(=({VSTR}|{MACRO})+)?)
SOPT		({SSTR}|{QSTR}|{MACRO}(\.|{SSTR}|{QSTR}|{MACRO})+)
NOPT		({SSTR}|(({IP4ADDR}(\/{V4MASK})?)|({IP6ADDR}(\/{V6MASK})?)))

MAPOPT		(fs|type|maptype|pref|sublink|cache)
MNTOPT		(opts|addopts|remopts)
FSOPTS		(rhost|rfs|dev|cachedir|mount|unmount|umount|delay)
CHEOPT		((mapdefault|none|inc|re|regexp|all)(,sync)?)
MAPTYPE		(file|nis|nisplus|ldap|hesiod|exec|ndbm|passwd|union)
FSTYPE_LOCAL	(link|linkx|lofs|ufs|ext2|ext3|ext4|xfs|jfs|cdfs|cachefs)
FSTYPE_NET	(nfs|nfsx|nfsl|host)
FSTYPE		(auto|program|direct|lustre|{FSTYPE_LOCAL}|{FSTYPE_NET})

OSSEL		(arch|karch|os|osver|full_os|vendor)
HSTSEL		(host|hostd|domain|byte|cluster)
NETSEL		(netnumber|network|wire|in_network)
USRSEL		(uid|gid)
MAPSEL		(key|map|path)
OTRSEL		(autodir|dollar)
BOLSEL		(true|false)

SELOPT		({OSSEL}|{HSTSEL}|{USRSEL}|{MAPSEL}|{OTRSEL})
SEL1ARG		(xhost|exists|{NETSEL}|{BOLSEL})
SEL2ARG		(netgrp|netgrpd)

CUTSEP		(\|\||\/)

%%

%{
	if (reset_start_state) {
		BEGIN START;
		reset_start_state = 0;
	}
%}

<START>{
	{NL} |
	\x00 { }

	{MAPOPT} {
		BEGIN(MAPOPTVAL);
		amd_copy_buffer();
		return MAP_OPTION;

	}

	{FSOPTS} {
		BEGIN(FSOPTVAL);
		amd_copy_buffer();
		return FS_OPTION;
	}

	{MNTOPT} {
		BEGIN(MNTOPTVAL);
		amd_copy_buffer();
		return MNT_OPTION;
	}

	{SELOPT} {
		BEGIN(SELOPTVAL);
		amd_copy_buffer();
		return SELECTOR;
	}

	"!"/({SEL1ARG}|{SEL2ARG}) { return NOT; }

	{SEL1ARG} {
		BEGIN(SELARGVAL);
		amd_copy_buffer();
		return SELECTOR;
	}

	{SEL2ARG} {
		BEGIN(SELARGVAL);
		amd_copy_buffer();
		return SELECTOR;
	}

	{CUTSEP} { return CUT; }

	"-" { return HYPHEN; }

	{OPTWS} { return SPACE; }

	#.*  { return COMMENT; }

	{OTHR} {
		amd_copy_buffer();
		return OTHER;
	}
}

<MAPOPTVAL>{
	{NL} {
		BEGIN(START);
		yyless(1);
	}

	\x00 {
		BEGIN(START);
		return SEPERATOR;
		yyless(1);
	}

	";" {
		BEGIN(START);
		return SEPERATOR;
	}

	{OPTWS} {
		BEGIN(START);
		return SPACE;
	}

	":=" { return OPTION_ASSIGN; }

	{FSTYPE} {
		amd_copy_buffer();
		return FS_TYPE;
	}

	{MAPTYPE} {
		amd_copy_buffer();
		return MAP_TYPE;
	}

	{CHEOPT} {
		amd_copy_buffer();
		return CACHE_OPTION;
	}

	{FOPT} {
		amd_copy_buffer();
		return FS_OPT_VALUE;
	}
}

<FSOPTVAL>{
	{NL} {
		BEGIN(START);
		yyless(1);
	}

	\x00 {
		BEGIN(START);
		return SEPERATOR;
		yyless(1);
	}

	";" {
		BEGIN(START);
		return SEPERATOR;
	}

	{OPTWS} {
		BEGIN(START);
		return SPACE;
	}

	":=" { return OPTION_ASSIGN; }

	{FOPT} {
		amd_copy_buffer();
		return FS_OPT_VALUE;
	}
}

<MNTOPTVAL>{
	{NL} {
		BEGIN(START);
		yyless(1);
	}

	\x00 {
		BEGIN(START);
		return SEPERATOR;
		yyless(1);
	}

	";" {
		BEGIN(START);
		return SEPERATOR;
	}

	{OPTWS} {
		BEGIN(START);
		return SPACE;
	}

	(:=)(,+)? { return OPTION_ASSIGN; }

	,+ { return COMMA; }

	"\"" { return QUOTE; }

	{OPTS} {
		amd_copy_buffer();
		return OPTION;
	}
}

<SELOPTVAL>{
	{NL} {
		BEGIN(START);
		yyless(1);
	}

	\x00 {
		BEGIN(START);
		return SEPERATOR;
		yyless(1);
	}

	";" {
		BEGIN(START);
		return SEPERATOR;
	}

	{OPTWS} {
		BEGIN(START);
		return SPACE;
	}

	"==" { return IS_EQUAL; }

	"!=" { return NOT_EQUAL; }

	{SOPT} {
		amd_copy_buffer();
		return SELECTOR_VALUE;
	}
}

<SELARGVAL>{
	{NL} {
		BEGIN(START);
		yyless(1);
	}

	\x00 {
		BEGIN(START);
		return SEPERATOR;
		yyless(1);
	}

	";" {
		BEGIN(START);
		return SEPERATOR;
	}

	"(" { return LBRACKET; }

	{NOPT} {
		amd_copy_buffer();
		return SEL_ARG_VALUE;
	}

	{SOPT}/"," {
		amd_copy_buffer();
		return SEL_ARG_VALUE;
	}

	"," { return COMMA; }

	{SOPT} {
		amd_copy_buffer();
		return SEL_ARG_VALUE;
	}

	{FOPT} {
		amd_copy_buffer();
		return SEL_ARG_VALUE;
	}

	")" { return RBRACKET; }
}

%%

#include "automount.h"

int amd_wrap(void)
{
	return 1;
}

static void amd_copy_buffer(void)
{
	if (amd_leng < 2048)
		strcpy(amd_lval.strtype, amd_text);
	else {
		strncpy(amd_lval.strtype, amd_text, 2047);
		amd_lval.strtype[2047] = '\0';
		logmsg("warning: truncated option near %s\n",
			&amd_lval.strtype[2030]);
	}
}

static void amd_echo(void)
{
	logmsg("%s\n", amd_text);
	return;
}

#ifdef FLEX_SCANNER

void amd_set_scan_buffer(const char *buffer)
{
	YY_FLUSH_BUFFER;
	reset_start_state = 1;

	line = buffer;
	line_pos = &line[0];
	/*
	 * Ensure buffer is 1 greater than string and is zeroed before
	 * the parse so we can fit the extra NULL which allows us to
	 * explicitly match an end of line within the buffer (ie. the
	 * need for 2 NULLS when parsing in memeory buffers).
	 */
	line_lim = line + strlen(buffer) + 1;
}

#define amd_min(a,b) (((a) < (b)) ? (a) : (b))

int amd_yyinput(char *buffer, int max_size)
{
	int n = amd_min(max_size, line_lim - line_pos);

	if (n > 0) {
		memcpy(buffer, line_pos, n);
		line_pos += n;
	}
	return n;
}

#else

void amd_set_scan_buffer(const char *buffer)
{
	line = buffer;
}

#endif
