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