1/*
2 * mksyntax.c - construct shell syntax table for fast char attribute lookup.
3 */
4
5/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
6
7   This file is part of GNU Bash, the Bourne Again SHell.
8
9   Bash is free software; you can redistribute it and/or modify it under
10   the terms of the GNU General Public License as published by the Free
11   Software Foundation; either version 2, or (at your option) any later
12   version.
13
14   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
15   WARRANTY; without even the implied warranty of MERCHANTABILITY or
16   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17   for more details.
18
19   You should have received a copy of the GNU General Public License along
20   with Bash; see the file COPYING.  If not, write to the Free Software
21   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22
23#include "config.h"
24
25#include <stdio.h>
26#include "bashansi.h"
27#include "chartypes.h"
28#include <errno.h>
29
30#ifdef HAVE_UNISTD_H
31#  include <unistd.h>
32#endif
33
34#include "syntax.h"
35
36extern int optind;
37extern char *optarg;
38
39#ifndef errno
40extern int errno;
41#endif
42
43#ifndef HAVE_STRERROR
44extern char *strerror();
45#endif
46
47struct wordflag {
48	int	flag;
49	char	*fstr;
50} wordflags[] = {
51	{ CWORD,	"CWORD" },
52	{ CSHMETA,	"CSHMETA" },
53	{ CSHBRK,	"CSHBRK" },
54	{ CBACKQ,	"CBACKQ" },
55	{ CQUOTE,	"CQUOTE" },
56	{ CSPECL,	"CSPECL" },
57	{ CEXP,		"CEXP" },
58	{ CBSDQUOTE,	"CBSDQUOTE" },
59	{ CBSHDOC,	"CBSHDOC" },
60	{ CGLOB,	"CGLOB" },
61	{ CXGLOB,	"CXGLOB" },
62	{ CXQUOTE,	"CXQUOTE" },
63	{ CSPECVAR,	"CSPECVAR" },
64	{ CSUBSTOP,	"CSUBSTOP" },
65	{ CBLANK,	"CBLANK" },
66};
67
68#define N_WFLAGS	(sizeof (wordflags) / sizeof (wordflags[0]))
69#define SYNSIZE		256
70
71int	lsyntax[SYNSIZE];
72int	debug;
73char	*progname;
74
75char	preamble[] = "\
76/*\n\
77 * This file was generated by mksyntax.  DO NOT EDIT.\n\
78 */\n\
79\n";
80
81char	includes[] = "\
82#include \"config.h\"\n\
83#include \"stdc.h\"\n\
84#include \"syntax.h\"\n\n";
85
86static void
87usage()
88{
89  fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname);
90  exit (2);
91}
92
93#ifdef INCLUDE_UNUSED
94static int
95getcflag (s)
96     char *s;
97{
98  int i;
99
100  for (i = 0; i < N_WFLAGS; i++)
101    if (strcmp (s, wordflags[i].fstr) == 0)
102      return wordflags[i].flag;
103  return -1;
104}
105#endif
106
107static char *
108cdesc (i)
109     int i;
110{
111  static char xbuf[16];
112
113  if (i == ' ')
114    return "SPC";
115  else if (ISPRINT (i))
116    {
117      xbuf[0] = i;
118      xbuf[1] = '\0';
119      return (xbuf);
120    }
121  else if (i == CTLESC)
122    return "CTLESC";
123  else if (i == CTLNUL)
124    return "CTLNUL";
125  else if (i == '\033')		/* ASCII */
126    return "ESC";
127
128  xbuf[0] = '\\';
129  xbuf[2] = '\0';
130
131  switch (i)
132    {
133#ifdef __STDC__
134    case '\a': xbuf[1] = 'a'; break;
135    case '\v': xbuf[1] = 'v'; break;
136#else
137    case '\007': xbuf[1] = 'a'; break;
138    case 0x0B: xbuf[1] = 'v'; break;
139#endif
140    case '\b': xbuf[1] = 'b'; break;
141    case '\f': xbuf[1] = 'f'; break;
142    case '\n': xbuf[1] = 'n'; break;
143    case '\r': xbuf[1] = 'r'; break;
144    case '\t': xbuf[1] = 't'; break;
145    default: sprintf (xbuf, "%d", i); break;
146    }
147
148  return xbuf;
149}
150
151static char *
152getcstr (f)
153     int f;
154{
155  int i;
156
157  for (i = 0; i < N_WFLAGS; i++)
158    if (f == wordflags[i].flag)
159      return (wordflags[i].fstr);
160  return ((char *)NULL);
161}
162
163static void
164addcstr (str, flag)
165     char *str;
166     int flag;
167{
168  char *s, *fstr;
169  unsigned char uc;
170
171  for (s = str; s && *s; s++)
172    {
173      uc = *s;
174
175      if (debug)
176	{
177	  fstr = getcstr (flag);
178	  fprintf(stderr, "added %s for character %s\n", fstr, cdesc(uc));
179	}
180
181      lsyntax[uc] |= flag;
182    }
183}
184
185static void
186addcchar (c, flag)
187     unsigned char c;
188     int flag;
189{
190  char *fstr;
191
192  if (debug)
193    {
194      fstr = getcstr (flag);
195      fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c));
196    }
197  lsyntax[c] |= flag;
198}
199
200static void
201addblanks ()
202{
203  register int i;
204  unsigned char uc;
205
206  for (i = 0; i < SYNSIZE; i++)
207    {
208      uc = i;
209      /* Since we don't call setlocale(), this defaults to the "C" locale, and
210	 the default blank characters will be space and tab. */
211      if (isblank (uc))
212	lsyntax[uc] |= CBLANK;
213    }
214}
215
216/* load up the correct flag values in lsyntax */
217static void
218load_lsyntax ()
219{
220  /* shell metacharacters */
221  addcstr (shell_meta_chars, CSHMETA);
222
223  /* shell word break characters */
224  addcstr (shell_break_chars, CSHBRK);
225
226  addcchar ('`', CBACKQ);
227
228  addcstr (shell_quote_chars, CQUOTE);
229
230  addcchar (CTLESC, CSPECL);
231  addcchar (CTLNUL, CSPECL);
232
233  addcstr (shell_exp_chars, CEXP);
234
235  addcstr (slashify_in_quotes, CBSDQUOTE);
236  addcstr (slashify_in_here_document, CBSHDOC);
237
238  addcstr (shell_glob_chars, CGLOB);
239
240#if defined (EXTENDED_GLOB)
241  addcstr (ext_glob_chars, CXGLOB);
242#endif
243
244  addcstr (shell_quote_chars, CXQUOTE);
245  addcchar ('\\', CXQUOTE);
246
247  addcstr ("@*#?-$!", CSPECVAR);	/* omits $0...$9 and $_ */
248
249  addcstr ("-=?+", CSUBSTOP);		/* OP in ${paramOPword} */
250
251  addblanks ();
252}
253
254static void
255dump_lflags (fp, ind)
256     FILE *fp;
257     int ind;
258{
259  int xflags, first, i;
260
261  xflags = lsyntax[ind];
262  first = 1;
263
264  if (xflags == 0)
265    fputs (wordflags[0].fstr, fp);
266  else
267    {
268      for (i = 1; i < N_WFLAGS; i++)
269	if (xflags & wordflags[i].flag)
270	  {
271	    if (first)
272	      first = 0;
273	    else
274	      putc ('|', fp);
275	    fputs (wordflags[i].fstr, fp);
276  	  }
277    }
278}
279
280static void
281wcomment (fp, i)
282     FILE *fp;
283     int i;
284{
285  fputs ("\t\t/* ", fp);
286
287  fprintf (fp, "%s", cdesc(i));
288
289  fputs (" */", fp);
290}
291
292static void
293dump_lsyntax (fp)
294     FILE *fp;
295{
296  int i;
297
298  fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE);
299  fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE);
300
301  for (i = 0; i < SYNSIZE; i++)
302    {
303      putc ('\t', fp);
304      dump_lflags (fp, i);
305      putc (',', fp);
306      wcomment (fp, i);
307      putc ('\n', fp);
308    }
309
310  fprintf (fp, "};\n");
311}
312
313int
314main(argc, argv)
315     int argc;
316     char **argv;
317{
318  int opt, i;
319  char *filename;
320  FILE *fp;
321
322  if ((progname = strrchr (argv[0], '/')) == 0)
323    progname = argv[0];
324  else
325    progname++;
326
327  filename = (char *)NULL;
328  debug = 0;
329
330  while ((opt = getopt (argc, argv, "do:")) != EOF)
331    {
332      switch (opt)
333	{
334	case 'd':
335	  debug = 1;
336	  break;
337	case 'o':
338	  filename = optarg;
339	  break;
340	default:
341	  usage();
342	}
343    }
344
345  argc -= optind;
346  argv += optind;
347
348  if (filename)
349    {
350      fp = fopen (filename, "w");
351      if (fp == 0)
352	{
353	  fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno));
354	  exit (1);
355	}
356    }
357  else
358    {
359      filename = "stdout";
360      fp = stdout;
361    }
362
363
364  for (i = 0; i < SYNSIZE; i++)
365    lsyntax[i] = CWORD;
366
367  load_lsyntax ();
368
369  fprintf (fp, "%s\n", preamble);
370  fprintf (fp, "%s\n", includes);
371
372  dump_lsyntax (fp);
373
374  if (fp != stdout)
375    fclose (fp);
376  exit (0);
377}
378
379
380#if !defined (HAVE_STRERROR)
381
382#include <bashtypes.h>
383#ifndef _MINIX
384#  include <sys/param.h>
385#endif
386
387#if defined (HAVE_UNISTD_H)
388#  include <unistd.h>
389#endif
390
391/* Return a string corresponding to the error number E.  From
392   the ANSI C spec. */
393#if defined (strerror)
394#  undef strerror
395#endif
396
397char *
398strerror (e)
399     int e;
400{
401  static char emsg[40];
402#if defined (HAVE_SYS_ERRLIST)
403  extern int sys_nerr;
404  extern char *sys_errlist[];
405
406  if (e > 0 && e < sys_nerr)
407    return (sys_errlist[e]);
408  else
409#endif /* HAVE_SYS_ERRLIST */
410    {
411      sprintf (emsg, "Unknown system error %d", e);
412      return (&emsg[0]);
413    }
414}
415#endif /* HAVE_STRERROR */
416