dnl  userv - lexer.l.m4
dnl  lexer, passed through m4 with defs from langauge.i4
/*
 *   Copyright (C)1996-1997,1999 Ian Jackson
 *  
 *   This 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; 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.
 *  
 *   You should have received a copy of the GNU General Public License
 *   along with userv; if not, write to the Free Software
 *   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

%{
include(language.i4)

#include <syslog.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <fnmatch.h>
#include <limits.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>

#include "config.h"
#include "common.h"
#include "daemon.h"
#include "lib.h"
#include "both.h"
#include "tokens.h"

#define HYPHEN '-'

typedef int directive_fnt(int dtoken);
static directive_fnt df_reject, df_execute, df_executefrompath;
static directive_fnt df_executefromdirectory, df_executebuiltin;
static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile;
static directive_fnt dfg_fdwant, dfg_setflag;
static directive_fnt df_reset, df_cd, df_userrcfile, df_include;
static directive_fnt df_includelookup, df_includedirectory;
static directive_fnt df_message, df_error, df_quit, df_eof;
static directive_fnt df_if, df_catchquit, df_errorspush;
static directive_fnt dfi_includeuserrcfile, dfi_includeclientconfig;
/* directive functions return:
 *  0 for success having scanned up to and including end of line but not beyond,
 *  or tokv_error or tokv_quit.
 * They expect to parse the whitespace before their parameters (if any).
 */

typedef int parmcondition_fnt(int ctoken, char *const *parmvalues, int *rtrue);
static parmcondition_fnt pcf_glob, pcf_range, pcf_grep;
/* all conditional functions return tokv_error for failure or 0 for success
 *  at parsing and testing, in which case *rtrue is set to 0 or 1.
 *  On success they have scanned up to and including the condition's
 *  terminating newline; the pcf_... functions expect to parse the whitespace
 *  between the parameter name and the condition's arguments.
 * Otherwise they return tokv_error.
 * The parameter-based conditionals take a list of parameter values
 * as obtained from the parameter functions and pa_parameter,
 * and do _not_ free it.
 */

typedef int parameter_fnt(int ptoken, char ***rvalues);
static parameter_fnt pf_service;
static parameter_fnt pf_callinguser, pf_serviceuser;
static parameter_fnt pf_callinggroup, pf_servicegroup;
static parameter_fnt pf_callingusershell, pf_serviceusershell;
/* Parameter functions return tokv_error or 0 for success at parsing
 * and determining the value, in which case *rvalues is made to be
 * a mallocd null-terminated array of pointers to mallocd strings.
 * freeparm can be used to free such an array.
 */

typedef int builtinserviceparse_fnt(char ***rnewargs);
static builtinserviceparse_fnt bispa_none, bispa_parameter;
/* These parse the arguments to a builtin service, including the
 * newline at the end of the line.  *rnewargs will initially be
 * null, indicating that no arguments are to be set; the function
 * may store a mallocd array of mallocd strings in it,
 * containing the arguments it wishes to have set (null-pointer
 * terminated).
 */

static int yylex(void);
/* Returns a token (which may be an eof or error exception) */

static directive_fnt *lr_dir;
static parmcondition_fnt *lr_parmcond;
static builtinserviceparse_fnt *lr_bispa;
static builtinserviceexec_fnt *lr_bisexec;
static parameter_fnt *lr_parameter;
static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag;
static int lr_flagval, lr_controlend;
static int lr_fdwant_readwrite; /* -1=never, 0=opt, 1=always */

/* Forward declarations of things used in lexer and parser */

struct parser_state {
  int lineno, reportlineno, notedreferer, isinternal;
  const char *filename;
  struct stat filestab;
  YY_BUFFER_STATE ybuf;
  struct parser_state *upstate;
};

static struct parser_state *cstate;

struct error_handling {
  int handling; /* One of the error handling modes tokt_ehandlemode */
  int logfacility, loglevel;
  int filekeep; /* File is in use by higher-level errors-push, leave it open */
  FILE *file;
  char *filename;
};

static struct error_handling eh = { tokv_word_errorstostderr, 0,0,0,0,0 };

static int dequote(char *inplace);
static void countnewlines(void);

#define YY_NO_UNPUT

%}

%option noyywrap

%%

dnl simple words
undivert(3)
changequote({*,*})
{*
[0-9]{1,8}		{
			  char *ep;
			  lr_min=lr_max= (int)strtoul(yytext,&ep,10);
			  assert(!*ep);
			  return tokv_ordinal;
			}
[0-9]{1,8}-[0-9]{1,8}	{
			  char *ep;
			  lr_min= (int)strtoul(yytext,&ep,10);
			  assert(*ep == HYPHEN);
			  assert(*++ep);
			  lr_max= (int)strtoul(ep,&ep,10);
			  assert(!*ep);
			  if (lr_max < lr_min)
			    return parseerrprint("fd range has min > max");
			  return tokv_fdrange;
			}
[0-9]{1,8}-		{
			  char *ep;
			  lr_min= (int)strtoul(yytext,&ep,10);
			  assert(*ep == HYPHEN);
			  assert(!*++ep);
			  lr_max=-1;
			  return tokv_fdstoend;
			}
([\ \t]*\\[\ \t]*\n[\ \t]*)+	countnewlines(); return tokv_lwsp;
[\ \t]+				return tokv_lwsp;
[\ \t]*\n		cstate->lineno++; return tokv_newline;
[\ \t]*\#[^\n]*\n	cstate->lineno++; return tokv_newline;
[\ \t]*\#[^\n]*		return parseerrprint("missing newline at eof after comment");
\"([^\\\"\n]|\\[a-z]|\\[0-9]{3}|\\x[0-9A-Fa-f]{2}|\\[[:punct:]]|\\[ \t]*\n)*\" {
			  countnewlines();
			  return dequote(yytext);
			}
[^\ \t\n\\\"]+		return tokv_barestring;
<<EOF>>			return tokv_eof;
\"			return parseerrprint("misquoted or unterminated string");
\\			return parseerrprint("unexpected backslash");
.			abort(); /* expect lex warning "rule cannot be matched" */
*}
changequote(`,')
%%

const char *const builtinservicehelpstrings[]= {
undivert(5)dnl
   0
};
`
#include "parser.c"
'
divert(-1)
undivert
