%{
/* This file is part of GDBM, the GNU data base manager.
Copyright (C) 1990-1991, 1993, 2007, 2011, 2013, 2016-2018 Free
Software Foundation, Inc.
GDBM 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 3, or (at your option)
any later version.
GDBM 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 GDBM. If not, see . */
#include "gdbmtool.h"
#include "gram.h"
struct point point;
/* Advance locus to the next line */
void
advance_line ()
{
++point.line;
point.col = 0;
}
#define YY_USER_ACTION \
do \
{ \
if (YYSTATE == 0) \
{ \
yylloc.beg = point; \
yylloc.beg.col++; \
} \
point.col += yyleng; \
yylloc.end = point; \
} \
while (0);
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
do \
{ \
result = input_read (yyin, buf, max_size); \
} \
while (0);
void string_begin (void);
void string_add (const char *s, int l);
void string_addc (int c);
char *string_end (void);
int unescape (int c);
struct context /* Input context */
{
struct context *parent; /* Pointer to the parent context */
struct locus locus; /* Locus */
struct point point;
int interactive;
ino_t ino; /* Inode number */
dev_t dev; /* Device number */
FILE *file; /* Input file */
YY_BUFFER_STATE buf; /* Buffer */
};
static struct context *context_tos;
static ino_t ino;
static dev_t dev;
int interactive; /* Are we running in interactive mode? */
static int initialized;
static void
context_push ()
{
struct context *cp = ecalloc (1, sizeof (*cp));
cp->locus = yylloc;
cp->point = point;
cp->interactive = interactive;
cp->ino = ino;
cp->dev = dev;
cp->file = yyin;
cp->buf = YY_CURRENT_BUFFER;
cp->parent = context_tos;
context_tos = cp;
}
int
context_pop ()
{
struct context *cp = context_tos;
fclose (yyin);
yyin = NULL;
free (point.file);
point.file = NULL;
memset (&yylloc, 0, sizeof (yylloc));
if (!cp)
return 1;
context_tos = cp->parent;
yylloc = cp->locus;
point = cp->point;
interactive = cp->interactive;
ino = cp->ino;
dev = cp->dev;
yyin = cp->file;
yy_delete_buffer (YY_CURRENT_BUFFER);
yy_switch_to_buffer (cp->buf);
return 0;
}
static struct context *
findctx (struct stat *st)
{
struct context *cp;
for (cp = context_tos; cp; cp = cp->parent)
if (cp->dev == st->st_dev && cp->ino == st->st_ino)
break;
return cp;
}
int
setsource (const char *name, int intr)
{
struct stat st;
struct context *cp;
FILE *fp;
if (strcmp (name, "-") == 0)
{
fp = stdin;
name = "stdin";
}
else
{
if (stat (name, &st))
{
terror (_("cannot open `%s': %s"), name, strerror (errno));
return -1;
}
else if (!S_ISREG (st.st_mode))
{
terror (_("%s is not a regular file"), name);
return -1;
}
cp = findctx (&st);
if (cp)
{
terror (_("recursive sourcing"));
if (cp->parent)
lerror (&cp->locus, _("%s already sourced here"), name);
return 1;
}
fp = fopen (name, "r");
if (!fp)
{
terror (_("cannot open %s for reading: %s"), name,
strerror (errno));
return 1;
}
}
if (yyin)
context_push ();
yyin = fp;
yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));
interactive = intr;
dev = st.st_dev;
ino = st.st_ino;
point.file = estrdup (name);
point.line = 1;
point.col = 0;
initialized = 1;
return 0;
}
%}
%option noinput
%option nounput
%x STR MLSTR DEF
WS [ \t][ \t]*
IDENT [a-zA-Z_][a-zA-Z_0-9-]*
N [0-9][0-9]*
P [1-9][0-9]*
X [0-9a-fA-F]
O [0-7]
%%
^[ \t]*#[ \t]*line[ \t].*\n {
char *p;
char *file = NULL;
int line, len;
for (p = strchr (yytext, '#') + 1; *p == ' ' || *p == '\t'; p++);
p += 4;
for (; *p == ' ' || *p == '\t'; p++);
line = strtol (p, &p, 10);
for (; *p == ' ' || *p == '\t'; p++);
if (*p == '"')
{
p++;
len = strcspn (p, "\"");
if (p[len] == 0)
{
yyerror (_("invalid #line statement"));
REJECT;
}
file = emalloc (len + 1);
memcpy (file, p, len);
file[len] = 0;
for (p += len + 1; *p == ' ' || *p == '\t'; p++);
}
if (*p != '\n' )
{
yyerror (_("invalid #line statement"));
free (file);
REJECT;
}
if (file)
point.file = file;
point.line = line;
point.col = 0;
}
#.*\n advance_line ();
#.* /* end-of-file comment */;
off { return T_OFF; }
pad { return T_PAD; }
0[xX]{X}{X}* { yylval.num = strtoul (yytext, NULL, 16);
return T_NUM; };
0{O}{O}* { yylval.num = strtoul (yytext, NULL, 8);
return T_NUM; };
0|{P} { yylval.num = strtoul (yytext, NULL, 10);
return T_NUM; };
^[ \t]*\? { return command_lookup ("help", &yylloc, &yylval.cmd); }
^[ \t]*{IDENT} { char *p = yytext + strspn (yytext, " \t");
return command_lookup (p, &yylloc, &yylval.cmd);
}
{IDENT} { if ((yylval.type = datadef_lookup (yytext)))
return T_TYPE;
else
{
yylval.string = estrdup (yytext);
return T_IDENT;
}
}
{IDENT} { yylval.string = estrdup (yytext);
return T_IDENT;
}
[^ \"\t\n\[\]{},=]+ { yylval.string = estrdup (yytext);
return T_WORD; }
\"[^\\\"\n]*\" { yylval.string = emalloc (yyleng - 1);
memcpy (yylval.string, yytext+1, yyleng-2);
yylval.string[yyleng-2] = 0;
return T_WORD; }
\"[^\\\"\n]*\\$ { string_begin ();
string_add (yytext + 1, yyleng - 2);
BEGIN (MLSTR); }
\"[^\\\"\n]*\\. { string_begin ();
string_add (yytext + 1, yyleng - 3);
string_addc (unescape (yytext[yyleng-1]));
BEGIN (STR); }
[^\\\"\n]*\" { if (yyleng > 1)
string_add (yytext, yyleng - 1);
yylval.string = string_end ();
BEGIN (INITIAL);
return T_WORD; }
[^\\\"\n]*\\$ { string_add (yytext, yyleng - 1); }
[^\\\"\n]*\\. { string_add (yytext, yyleng - 2);
string_addc (unescape (yytext[yyleng-1])); }
{WS} ;
\n { advance_line (); }
\n { advance_line (); return '\n'; }
. return yytext[0];
%%
int
yywrap ()
{
return context_pop ();
}
void
begin_def (void)
{
BEGIN (DEF);
}
void
end_def (void)
{
BEGIN (INITIAL);
}
void
print_prompt_at_bol (void)
{
if (YY_AT_BOL ())
{
char *s = make_prompt ();
fputs (s, stdout);
fflush (stdout);
free (s);
}
}
struct strseg
{
struct strseg *next;
int len;
char ptr[1];
};
static struct strseg *strseg_head, *strseg_tail;
void
string_begin (void)
{
strseg_head = strseg_tail = NULL;
}
void
strseg_attach (struct strseg *seg)
{
seg->next = NULL;
if (strseg_tail)
strseg_tail->next = seg;
else
strseg_head = seg;
strseg_tail = seg;
}
void
string_add (const char *s, int l)
{
struct strseg *seg = emalloc (sizeof (*seg) + l);
memcpy (seg->ptr, s, l);
seg->len = l;
strseg_attach (seg);
}
void
string_addc (int c)
{
struct strseg *seg = emalloc (sizeof (*seg));
seg->ptr[0] = c;
seg->len = 1;
strseg_attach (seg);
}
char *
string_end (void)
{
int len = 1;
struct strseg *seg;
char *ret, *p;
for (seg = strseg_head; seg; seg = seg->next)
len += seg->len;
ret = emalloc (len);
p = ret;
for (seg = strseg_head; seg; )
{
struct strseg *next = seg->next;
memcpy (p, seg->ptr, seg->len);
p += seg->len;
free (seg);
seg = next;
}
*p = 0;
strseg_head = strseg_tail = NULL;
return ret;
}
static char transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
int
unescape (int c)
{
char *p;
for (p = transtab; *p; p += 2)
{
if (*p == c)
return p[1];
}
return c;
}
int
escape (int c)
{
char *p;
for (p = transtab + sizeof (transtab) - 2; p > transtab; p -= 2)
{
if (*p == c)
return p[-1];
}
return 0;
}
void
vlerror (struct locus *loc, const char *fmt, va_list ap)
{
if (!interactive)
fprintf (stderr, "%s: ", progname);
if (initialized && loc && loc->beg.file)
{
YY_LOCATION_PRINT (stderr, *loc);
fprintf (stderr, ": ");
}
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
}
void
lerror (struct locus *loc, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vlerror (loc, fmt, ap);
va_end (ap);
}
static struct slist *
pe_file_name (void)
{
return file_name ? slist_new (file_name) : NULL;
}
static struct slist *
pe_program_name (void)
{
return slist_new (progname);
}
static struct slist *
pe_package_name (void)
{
return slist_new (PACKAGE_NAME);
}
static struct slist *
pe_program_version (void)
{
return slist_new (PACKAGE_VERSION);
}
static struct slist *
pe_space (void)
{
return slist_new (" ");
}
struct prompt_exp
{
int ch;
struct slist *(*fun) (void);
};
struct prompt_exp prompt_exp[] = {
{ 'f', pe_file_name },
{ 'p', pe_program_name },
{ 'P', pe_package_name },
{ 'v', pe_program_version },
{ '_', pe_space },
{ 0 }
};
static int
expand_char (int c, struct slist **tailp)
{
struct prompt_exp *p;
if (c && c != '%')
{
for (p = prompt_exp; p->ch; p++)
{
if (c == p->ch)
{
struct slist *s = p->fun ();
if (s)
slist_insert (tailp, s);
return 0;
}
}
}
return 1;
}
char const *
psname (void)
{
if (YYSTATE == DEF || YYSTATE == MLSTR)
return "ps2";
return "ps1";
}
char *
make_prompt (void)
{
const char *s;
const char *prompt;
struct slist *head = NULL, *tail = NULL, *p;
char *ret, *end;
size_t len;
switch (variable_get (psname (), VART_STRING, (void *) &prompt))
{
case VAR_OK:
break;
case VAR_ERR_NOTSET:
return NULL;
default:
abort ();
}
for (s = prompt; *s; )
{
if (*s == '%' && s[1])
{
if (s > prompt)
{
slist_insert (&tail, slist_new_l (prompt, s - prompt));
if (!head)
head = tail;
}
if (expand_char (s[1], &tail) == 0)
{
if (!head)
head = tail;
prompt = s + 2;
}
else
prompt = s;
s += 2;
}
else
++s;
}
if (s > prompt)
{
slist_insert (&tail, slist_new_l (prompt, s - prompt));
if (!head)
head = tail;
}
len = 0;
for (p = head; p; p = p->next)
len += strlen (p->str);
ret = emalloc (len + 1);
end = ret;
for (p = head; p; p = p->next)
{
s = p->str;
while (*s)
*end++ = *s++;
}
*end = 0;
slist_free (head);
return ret;
}