add changelog
[platform/upstream/gdbm.git] / src / lex.l
1 %{
2 /* This file is part of GDBM, the GNU data base manager.
3    Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation,
4    Inc.
5
6    GDBM is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    GDBM is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GDBM. If not, see <http://www.gnu.org/licenses/>.    */
18
19 #include "gdbmtool.h"
20 #include "gram.h"
21
22 struct point point;
23  
24 /* Advance locus to the next line */
25 void
26 advance_line ()
27 {
28   ++point.line;
29   point.col = 0;
30 }
31
32 #define YY_USER_ACTION                                      \
33   do                                                        \
34     {                                                       \
35       if (YYSTATE == 0)                                     \
36         {                                                   \
37           yylloc.beg = point;                               \
38           yylloc.beg.col++;                                 \
39         }                                                   \
40       point.col += yyleng;                                  \
41       yylloc.end = point;                                   \
42     }                                                       \
43   while (0);
44
45 #undef YY_INPUT
46 #define YY_INPUT(buf,result,max_size)                                   \
47   do                                                                    \
48     {                                                                   \
49       result = read_input (buf, max_size);                              \
50     }                                                                   \
51   while (0);
52  
53 void string_begin (void);
54 void string_add (const char *s, int l);
55 void string_addc (int c);
56 char *string_end (void);
57 int unescape (int c);
58
59 static ssize_t read_input (char *buf, size_t size);
60
61 struct context                /* Input context */
62 {
63   struct context *parent;     /* Pointer to the parent context */
64   struct locus locus;         /* Locus */
65   struct point point;
66   int interactive;
67   ino_t ino;                  /* Inode number */ 
68   dev_t dev;                  /* Device number */
69   FILE *file;                 /* Input file */
70   YY_BUFFER_STATE buf;        /* Buffer */
71 };
72
73 static struct context *context_tos;
74 static ino_t ino;
75 static dev_t dev;
76 int interactive;              /* Are we running in interactive mode? */
77 static int initialized;
78  
79 static void
80 context_push ()
81 {
82   struct context *cp = ecalloc (1, sizeof (*cp));
83
84   cp->locus = yylloc;
85   cp->point = point;
86   cp->interactive = interactive;
87   cp->ino = ino;
88   cp->dev = dev;
89   cp->file = yyin;
90   cp->buf = YY_CURRENT_BUFFER;
91   cp->parent = context_tos;
92   context_tos = cp;
93 }
94
95 int
96 context_pop ()
97 {
98   struct context *cp = context_tos;
99
100   fclose (yyin);
101   yyin = NULL;
102   free (point.file);
103   point.file = NULL;
104   memset (&yylloc, 0, sizeof (yylloc));
105   
106   if (!cp)
107     return 1;
108
109   context_tos = cp->parent;
110   
111   yylloc = cp->locus;
112   point = cp->point;
113   interactive = cp->interactive;
114   ino = cp->ino;
115   dev = cp->dev;
116   yyin = cp->file;
117   yy_delete_buffer (YY_CURRENT_BUFFER);
118   yy_switch_to_buffer (cp->buf);
119
120   return 0;
121 }
122
123 static struct context *
124 findctx (struct stat *st)
125 {
126   struct context *cp;
127
128   for (cp = context_tos; cp; cp = cp->parent)
129     if (cp->dev == st->st_dev && cp->ino == st->st_ino)
130       break;
131   return cp;
132 }
133  
134 int
135 setsource (const char *name, int intr)
136 {
137   struct stat st;
138   struct context *cp;
139   FILE *fp;
140   
141   if (strcmp (name, "-") == 0)
142     {
143       fp = stdin;
144       name = "stdin";
145     }
146   else
147     {
148       if (stat (name, &st))
149         {
150           terror (_("cannot open `%s': %s"), name, strerror (errno));
151           return -1;
152         }
153       else if (!S_ISREG (st.st_mode))
154         {
155           terror (_("%s is not a regular file"), name);
156           return -1;
157         }
158
159       cp = findctx (&st);
160       if (cp)
161         {
162           terror (_("recursive sourcing"));
163           if (cp->parent)
164             lerror (&cp->locus, _("%s already sourced here"), name);
165           return 1;
166         }
167       
168       fp = fopen (name, "r");
169       if (!fp)
170         {
171           terror (_("cannot open %s for reading: %s"), name,
172                         strerror (errno));
173           return 1;
174         }
175     }
176   
177   if (yyin)
178     context_push ();
179
180   yyin = fp;
181   yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));
182
183   interactive = intr;
184   dev = st.st_dev;
185   ino = st.st_ino;
186   
187   point.file = estrdup (name);
188   point.line = 1;
189   point.col = 0;
190
191   initialized = 1;
192   
193   return 0;
194 }
195 %}
196
197 %option nounput
198
199 %x STR MLSTR DEF
200
201 WS [ \t][ \t]*
202 IDENT [a-zA-Z_][a-zA-Z_0-9-]*
203 N [0-9][0-9]*
204 P [1-9][0-9]*
205 X [0-9a-fA-F]
206 O [0-7]
207
208 %%
209 ^[ \t]*#[ \t]*line[ \t].*\n {
210   char *p;
211   char *file = NULL;
212   int line, len;
213   
214   for (p = strchr (yytext, '#') + 1; *p == ' ' || *p == '\t'; p++);
215   p += 4;
216   for (; *p == ' ' || *p == '\t'; p++);
217
218   line = strtol (p, &p, 10);
219   for (; *p == ' ' || *p == '\t'; p++);
220
221   if (*p == '"')
222     {
223       p++;
224       len = strcspn (p, "\"");
225       if (p[len] == 0)
226         {
227           yyerror (_("invalid #line statement"));
228           REJECT;
229         }
230       file = emalloc (len + 1);
231       memcpy (file, p, len);
232       file[len] = 0;
233       for (p += len + 1; *p == ' ' || *p == '\t'; p++);
234     }
235   if (*p != '\n' )
236     {
237       yyerror (_("invalid #line statement"));
238       free (file);
239       REJECT;
240     }
241   if (file)
242     point.file = file;
243   point.line = line;
244   point.col = 0;
245 }
246 #.*\n              advance_line ();
247 #.*     /* end-of-file comment */;
248
249 <DEF>off           { return T_OFF; }
250 <DEF>pad           { return T_PAD; }
251 <DEF>0[xX]{X}{X}*  { yylval.num = strtoul (yytext, NULL, 16);
252                      return T_NUM; };
253 <DEF>0{O}{O}*      { yylval.num = strtoul (yytext, NULL, 8);
254                      return T_NUM; };
255 <DEF>0|{P}         { yylval.num = strtoul (yytext, NULL, 10);
256                      return T_NUM; };
257 ^[ \t]*\?          { return command_lookup ("help", &yylloc, &yylval.cmd); }
258 ^[ \t]*{IDENT}     { char *p = yytext + strspn (yytext, " \t");
259                      return command_lookup (p, &yylloc, &yylval.cmd);
260                    }
261 <DEF>{IDENT}       { if ((yylval.type = datadef_lookup (yytext)))
262                        return T_TYPE;
263                      else
264                        {
265                          yylval.string = estrdup (yytext);
266                          return T_IDENT;
267                        }
268                    }
269 {IDENT}            { yylval.string = estrdup (yytext);
270                      return T_IDENT;
271                    }
272 <INITIAL,DEF>[^ \"\t\n\[\]{},=]+  { yylval.string = estrdup (yytext);
273                                     return T_WORD; }
274 \"[^\\\"\n]*\"     { yylval.string = emalloc (yyleng - 1);
275                      memcpy (yylval.string, yytext+1, yyleng-2);
276                      yylval.string[yyleng-2] = 0;
277                      return T_WORD; }
278 \"[^\\\"\n]*\\$    { string_begin ();
279                      string_add (yytext + 1, yyleng - 2);
280                      BEGIN (MLSTR); }
281 \"[^\\\"\n]*\\.    { string_begin ();
282                      string_add (yytext + 1, yyleng - 3);
283                      string_addc (unescape (yytext[yyleng-1]));
284                      BEGIN (STR); }
285 <STR,MLSTR>[^\\\"\n]*\"  { if (yyleng > 1)
286                              string_add (yytext, yyleng - 1);
287                            yylval.string = string_end ();
288                            BEGIN (INITIAL);
289                            return T_WORD; }
290 <STR,MLSTR>[^\\\"\n]*\\$ { string_add (yytext, yyleng - 1); }
291 <STR,MLSTR>[^\\\"\n]*\\. { string_add (yytext, yyleng - 2);
292                            string_addc (unescape (yytext[yyleng-1])); }
293 <INITIAL,DEF>{WS}  ;
294 <DEF>\n            { advance_line (); }
295 \n                 { advance_line (); return '\n'; }
296 <INITIAL,DEF>.     return yytext[0];
297 %%
298
299 int
300 yywrap ()
301 {
302   return context_pop ();
303 }
304
305 void
306 begin_def (void)
307 {
308   BEGIN (DEF);
309 }
310
311 void
312 end_def (void)
313 {
314   BEGIN (INITIAL);
315
316
317 static ssize_t
318 read_input (char *buf, size_t size)
319 {
320   if (interactive)
321     {
322       if (YY_AT_BOL ())
323         print_prompt ();
324       if (fgets (buf, size, yyin) == NULL)
325         return 0;
326       return strlen (buf);
327     }
328   return fread (buf, 1, size, yyin);
329 }
330   
331 \f
332 struct strseg
333 {
334   struct strseg *next;
335   int len;
336   char ptr[1];
337 };
338
339 static struct strseg *strseg_head, *strseg_tail;
340
341 void
342 string_begin (void)
343 {
344   strseg_head = strseg_tail = NULL;
345 }
346
347 void
348 strseg_attach (struct strseg *seg)
349 {
350   seg->next = NULL;
351   if (strseg_tail)
352     strseg_tail->next = seg;
353   else
354     strseg_head = seg;
355   strseg_tail = seg;
356 }  
357
358 void
359 string_add (const char *s, int l)
360 {
361   struct strseg *seg = emalloc (sizeof (*seg) + l);
362   memcpy (seg->ptr, s, l);
363   seg->len = l;
364   strseg_attach (seg);
365 }
366
367 void
368 string_addc (int c)
369 {
370   struct strseg *seg = emalloc (sizeof (*seg));
371   seg->ptr[0] = c;
372   seg->len = 1;
373   strseg_attach (seg);
374 }
375
376 char *
377 string_end (void)
378 {
379   int len = 1;
380   struct strseg *seg;
381   char *ret, *p;
382   
383   for (seg = strseg_head; seg; seg = seg->next)
384     len += seg->len;
385
386   ret = emalloc (len);
387   p = ret;
388   for (seg = strseg_head; seg; )
389     {
390       struct strseg *next = seg->next;
391       memcpy (p, seg->ptr, seg->len);
392       p += seg->len;
393       free (seg);
394       seg = next;
395     }
396   *p = 0;
397
398   strseg_head = strseg_tail = NULL;
399
400   return ret;
401 }
402
403 static char transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
404
405 int
406 unescape (int c)
407 {
408   char *p;
409
410   for (p = transtab; *p; p += 2)
411     {
412       if (*p == c)
413         return p[1];
414     }
415   return c;
416 }
417
418 int
419 escape (int c)
420 {
421   char *p;
422   for (p = transtab + sizeof (transtab) - 2; p > transtab; p -= 2)
423     {
424       if (*p == c)
425         return p[-1];
426     }
427   return 0;
428 }
429
430 void
431 vlerror (struct locus *loc, const char *fmt, va_list ap)
432 {
433   if (!interactive)
434     fprintf (stderr, "%s: ", progname);
435   if (initialized && loc && loc->beg.file)
436     {
437       YY_LOCATION_PRINT (stderr, *loc);
438       fprintf (stderr, ": ");
439     }
440   vfprintf (stderr, fmt, ap);
441   fputc ('\n', stderr);
442 }
443
444 void
445 lerror (struct locus *loc, const char *fmt, ...)
446 {
447   va_list ap;
448
449   va_start (ap, fmt);
450   vlerror (loc, fmt, ap);
451   va_end (ap);
452 }
453
454 \f
455 struct prompt_exp;
456
457 void
458 pe_file_name (struct prompt_exp *p)
459 {
460   if (file_name)
461     fwrite (file_name, strlen (file_name), 1, stdout);
462 }
463
464 void
465 pe_program_name (struct prompt_exp *p)
466 {
467   fwrite (progname, strlen (progname), 1, stdout);
468 }
469
470 void
471 pe_package_name (struct prompt_exp *p)
472 {
473   fwrite (PACKAGE_NAME, sizeof (PACKAGE_NAME) - 1, 1, stdout);
474 }
475
476 void
477 pe_program_version (struct prompt_exp *p)
478 {
479   fwrite (PACKAGE_VERSION, sizeof (PACKAGE_VERSION) - 1, 1, stdout);
480 }
481
482 void
483 pe_space (struct prompt_exp *p)
484 {
485   fwrite (" ", 1, 1, stdout);
486 }
487
488 struct prompt_exp
489 {
490   int ch;
491   void (*fun) (struct prompt_exp *);
492   char *cache;
493 };
494
495 struct prompt_exp prompt_exp[] = {
496   { 'f', pe_file_name },
497   { 'p', pe_program_name },
498   { 'P', pe_package_name },
499   { 'v', pe_program_version },
500   { '_', pe_space },
501   { 0 }
502 };
503
504 static void
505 expand_char (int c)
506 {
507   struct prompt_exp *p;
508
509   if (c && c != '%')
510     {
511       for (p = prompt_exp; p->ch; p++)
512         {
513           if (c == p->ch)
514             {
515               if (p->cache)
516                 free (p->cache);
517               return p->fun (p);
518             }
519         }
520     }
521   putchar ('%');
522   putchar (c);
523 }
524
525 char const *
526 psname ()
527 {
528   if (YYSTATE == DEF || YYSTATE == MLSTR)
529     return "ps2";
530   return "ps1";
531 }
532
533 void
534 print_prompt ()
535 {
536   const char *s;
537   const char *prompt;
538
539   switch (variable_get (psname (), VART_STRING, (void *) &prompt))
540     {
541     case VAR_OK:
542       break;
543
544     case VAR_ERR_NOTSET:
545       return;
546       
547     default:
548       abort ();
549     }
550   
551   for (s = prompt; *s; s++)
552     {
553       if (*s == '%')
554         {
555           if (!*++s)
556             {
557               putchar ('%');
558               break;
559             }
560           expand_char (*s);
561         }
562       else
563         putchar (*s);
564     }
565
566   fflush (stdout);
567 }
568