11e51346jkim/* $Id: main.c,v 1.69 2019/11/25 23:24:36 Tom.Shields Exp $ */
226a93febapt
326a93febapt#include <signal.h>
41e51346jkim#if !defined(_WIN32) || defined(__MINGW32__)
526a93febapt#include <unistd.h>		/* for _exit() */
63c84e00bapt#else
73c84e00bapt#include <stdlib.h>		/* for _exit() */
83c84e00bapt#endif
926a93febapt
1026a93febapt#include "defs.h"
1126a93febapt
1295d4c53bapt#ifdef HAVE_MKSTEMP
1395d4c53bapt# define USE_MKSTEMP 1
1495d4c53bapt#elif defined(HAVE_FCNTL_H)
1595d4c53bapt# define USE_MKSTEMP 1
1695d4c53bapt# include <fcntl.h>		/* for open(), O_EXCL, etc. */
1726a93febapt#else
1826a93febapt# define USE_MKSTEMP 0
1926a93febapt#endif
2026a93febapt
2126a93febapt#if USE_MKSTEMP
2226a93febapt#include <sys/types.h>
2326a93febapt#include <sys/stat.h>
2426a93febapt
2526a93febapttypedef struct _my_tmpfiles
2626a93febapt{
2726a93febapt    struct _my_tmpfiles *next;
2826a93febapt    char *name;
2926a93febapt}
3026a93febaptMY_TMPFILES;
3126a93febapt
3226a93febaptstatic MY_TMPFILES *my_tmpfiles;
3326a93febapt#endif /* USE_MKSTEMP */
3426a93febapt
3526a93febaptchar dflag;
361e51346jkimchar dflag2;
3726a93febaptchar gflag;
3826a93febaptchar iflag;
3926a93febaptchar lflag;
4026a93febaptstatic char oflag;
4126a93febaptchar rflag;
4226a93febaptchar sflag;
4326a93febaptchar tflag;
4426a93febaptchar vflag;
4526a93febapt
4626a93febaptconst char *symbol_prefix;
4726a93febaptconst char *myname = "yacc";
4826a93febapt
4926a93febaptint lineno;
5026a93febaptint outline;
5126a93febapt
5226a93febaptstatic char default_file_prefix[] = "y";
5326a93febapt
5426a93febaptstatic char *file_prefix = default_file_prefix;
5526a93febapt
5626a93febaptchar *code_file_name;
57e7d342bjkimchar *input_file_name;
58e7d342bjkimsize_t input_file_name_len = 0;
5926a93febaptchar *defines_file_name;
6026a93febaptchar *externs_file_name;
6126a93febapt
6226a93febaptstatic char *graph_file_name;
6326a93febaptstatic char *output_file_name;
6426a93febaptstatic char *verbose_file_name;
6526a93febapt
6626a93febaptFILE *action_file;	/*  a temp file, used to save actions associated    */
6726a93febapt			/*  with rules until the parser is written          */
6826a93febaptFILE *code_file;	/*  y.code.c (used when the -r option is specified) */
6926a93febaptFILE *defines_file;	/*  y.tab.h                                         */
7026a93febaptFILE *externs_file;	/*  y.tab.i                                         */
7126a93febaptFILE *input_file;	/*  the input file                                  */
7226a93febaptFILE *output_file;	/*  y.tab.c                                         */
7326a93febaptFILE *text_file;	/*  a temp file, used to save text until all        */
7426a93febapt			/*  symbols have been defined                       */
7526a93febaptFILE *union_file;	/*  a temp file, used to save the union             */
7626a93febapt			/*  definition until all symbol have been           */
7726a93febapt			/*  defined                                         */
7826a93febaptFILE *verbose_file;	/*  y.output                                        */
7926a93febaptFILE *graph_file;	/*  y.dot                                           */
8026a93febapt
813c84e00baptValue_t nitems;
823c84e00baptValue_t nrules;
833c84e00baptValue_t nsyms;
843c84e00baptValue_t ntokens;
853c84e00baptValue_t nvars;
8626a93febapt
8726a93febaptValue_t start_symbol;
8826a93febaptchar **symbol_name;
8926a93febaptchar **symbol_pname;
9026a93febaptValue_t *symbol_value;
913c84e00baptValue_t *symbol_prec;
9226a93febaptchar *symbol_assoc;
9326a93febapt
9426a93febaptint pure_parser;
95c2f7afcbaptint token_table;
96fe9f57ajkimint error_verbose;
973c84e00bapt
983c84e00bapt#if defined(YYBTYACC)
993c84e00baptValue_t *symbol_pval;
1003c84e00baptchar **symbol_destructor;
1013c84e00baptchar **symbol_type_tag;
1023c84e00baptint locations = 0;	/* default to no position processing */
1033c84e00baptint backtrack = 0;	/* default is no backtracking */
104fe9f57ajkimchar *initial_action = NULL;
1053c84e00bapt#endif
1063c84e00bapt
10726a93febaptint exit_code;
10826a93febapt
10926a93febaptValue_t *ritem;
11026a93febaptValue_t *rlhs;
11126a93febaptValue_t *rrhs;
11226a93febaptValue_t *rprec;
11326a93febaptAssoc_t *rassoc;
11426a93febaptValue_t **derives;
11526a93febaptchar *nullable;
11626a93febapt
11726a93febapt/*
11826a93febapt * Since fclose() is called via the signal handler, it might die.  Don't loop
11926a93febapt * if there is a problem closing a file.
12026a93febapt */
12126a93febapt#define DO_CLOSE(fp) \
12226a93febapt	if (fp != 0) { \
12326a93febapt	    FILE *use = fp; \
12426a93febapt	    fp = 0; \
12526a93febapt	    fclose(use); \
12626a93febapt	}
12726a93febapt
12826a93febaptstatic int got_intr = 0;
12926a93febapt
13026a93febaptvoid
13126a93febaptdone(int k)
13226a93febapt{
13326a93febapt    DO_CLOSE(input_file);
13426a93febapt    DO_CLOSE(output_file);
1353c84e00bapt    if (iflag)
1363c84e00bapt	DO_CLOSE(externs_file);
1373c84e00bapt    if (rflag)
1383c84e00bapt	DO_CLOSE(code_file);
13926a93febapt
14026a93febapt    DO_CLOSE(action_file);
14126a93febapt    DO_CLOSE(defines_file);
14226a93febapt    DO_CLOSE(graph_file);
14326a93febapt    DO_CLOSE(text_file);
14426a93febapt    DO_CLOSE(union_file);
14526a93febapt    DO_CLOSE(verbose_file);
14626a93febapt
14726a93febapt    if (got_intr)
14826a93febapt	_exit(EXIT_FAILURE);
14926a93febapt
15026a93febapt#ifdef NO_LEAKS
15126a93febapt    if (rflag)
15226a93febapt	DO_FREE(code_file_name);
15326a93febapt
1541e51346jkim    if (dflag && !dflag2)
15526a93febapt	DO_FREE(defines_file_name);
15626a93febapt
15726a93febapt    if (iflag)
15826a93febapt	DO_FREE(externs_file_name);
15926a93febapt
16026a93febapt    if (oflag)
16126a93febapt	DO_FREE(output_file_name);
16226a93febapt
16326a93febapt    if (vflag)
16426a93febapt	DO_FREE(verbose_file_name);
16526a93febapt
16626a93febapt    if (gflag)
16726a93febapt	DO_FREE(graph_file_name);
16826a93febapt
16926a93febapt    lr0_leaks();
17026a93febapt    lalr_leaks();
17126a93febapt    mkpar_leaks();
17208d24c3bapt    mstring_leaks();
17326a93febapt    output_leaks();
17426a93febapt    reader_leaks();
17526a93febapt#endif
17626a93febapt
17726a93febapt    exit(k);
17826a93febapt}
17926a93febapt
18026a93febaptstatic void
18126a93febaptonintr(int sig GCC_UNUSED)
18226a93febapt{
18326a93febapt    got_intr = 1;
18426a93febapt    done(EXIT_FAILURE);
18526a93febapt}
18626a93febapt
18726a93febaptstatic void
18826a93febaptset_signals(void)
18926a93febapt{
19026a93febapt#ifdef SIGINT
19126a93febapt    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
19226a93febapt	signal(SIGINT, onintr);
19326a93febapt#endif
19426a93febapt#ifdef SIGTERM
19526a93febapt    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
19626a93febapt	signal(SIGTERM, onintr);
19726a93febapt#endif
19826a93febapt#ifdef SIGHUP
19926a93febapt    if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
20026a93febapt	signal(SIGHUP, onintr);
20126a93febapt#endif
20226a93febapt}
20326a93febapt
20426a93febaptstatic void
20526a93febaptusage(void)
20626a93febapt{
20726a93febapt    static const char *msg[] =
20826a93febapt    {
20926a93febapt	""
21026a93febapt	,"Options:"
21126a93febapt	,"  -b file_prefix        set filename prefix (default \"y.\")"
2123c84e00bapt	,"  -B                    create a backtracking parser"
2133c84e00bapt	,"  -d                    write definitions (" DEFINES_SUFFIX ")"
2141e51346jkim	,"  -H defines_file       write definitions to defines_file"
21526a93febapt	,"  -i                    write interface (y.tab.i)"
21626a93febapt	,"  -g                    write a graphical description"
21726a93febapt	,"  -l                    suppress #line directives"
2183c84e00bapt	,"  -L                    enable position processing, e.g., \"%locations\""
2193c84e00bapt	,"  -o output_file        (default \"" OUTPUT_SUFFIX "\")"
22026a93febapt	,"  -p symbol_prefix      set symbol prefix (default \"yy\")"
22126a93febapt	,"  -P                    create a reentrant parser, e.g., \"%pure-parser\""
22226a93febapt	,"  -r                    produce separate code and table files (y.code.c)"
22326a93febapt	,"  -s                    suppress #define's for quoted names in %token lines"
22426a93febapt	,"  -t                    add debugging support"
22526a93febapt	,"  -v                    write description (y.output)"
22626a93febapt	,"  -V                    show version information and exit"
22726a93febapt    };
22826a93febapt    unsigned n;
22926a93febapt
23026a93febapt    fflush(stdout);
23126a93febapt    fprintf(stderr, "Usage: %s [options] filename\n", myname);
23226a93febapt    for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n)
23326a93febapt	fprintf(stderr, "%s\n", msg[n]);
23426a93febapt
2351e51346jkim    exit(EXIT_FAILURE);
23626a93febapt}
23726a93febapt
23826a93febaptstatic void
23926a93febaptsetflag(int ch)
24026a93febapt{
24126a93febapt    switch (ch)
24226a93febapt    {
2433c84e00bapt    case 'B':
2443c84e00bapt#if defined(YYBTYACC)
2453c84e00bapt	backtrack = 1;
2463c84e00bapt#else
2473c84e00bapt	unsupported_flag_warning("-B", "reconfigure with --enable-btyacc");
2483c84e00bapt#endif
2493c84e00bapt	break;
2503c84e00bapt
25126a93febapt    case 'd':
25226a93febapt	dflag = 1;
2531e51346jkim	dflag2 = 0;
25426a93febapt	break;
25526a93febapt
25626a93febapt    case 'g':
25726a93febapt	gflag = 1;
25826a93febapt	break;
25926a93febapt
26026a93febapt    case 'i':
26126a93febapt	iflag = 1;
26226a93febapt	break;
26326a93febapt
26426a93febapt    case 'l':
26526a93febapt	lflag = 1;
26626a93febapt	break;
26726a93febapt
2683c84e00bapt    case 'L':
2693c84e00bapt#if defined(YYBTYACC)
2703c84e00bapt	locations = 1;
2713c84e00bapt#else
2722347331jkim	unsupported_flag_warning("-L", "reconfigure with --enable-btyacc");
2733c84e00bapt#endif
2743c84e00bapt	break;
2753c84e00bapt
27626a93febapt    case 'P':
27726a93febapt	pure_parser = 1;
27826a93febapt	break;
27926a93febapt
28026a93febapt    case 'r':
28126a93febapt	rflag = 1;
28226a93febapt	break;
28326a93febapt
28426a93febapt    case 's':
28526a93febapt	sflag = 1;
28626a93febapt	break;
28726a93febapt
28826a93febapt    case 't':
28926a93febapt	tflag = 1;
29026a93febapt	break;
29126a93febapt
29226a93febapt    case 'v':
29326a93febapt	vflag = 1;
29426a93febapt	break;
29526a93febapt
29626a93febapt    case 'V':
29726a93febapt	printf("%s - %s\n", myname, VERSION);
29826a93febapt	exit(EXIT_SUCCESS);
29926a93febapt
30026a93febapt    case 'y':
30126a93febapt	/* noop for bison compatibility. byacc is already designed to be posix
30226a93febapt	 * yacc compatible. */
30326a93febapt	break;
30426a93febapt
30526a93febapt    default:
30626a93febapt	usage();
30726a93febapt    }
30826a93febapt}
30926a93febapt
31026a93febaptstatic void
31126a93febaptgetargs(int argc, char *argv[])
31226a93febapt{
31326a93febapt    int i;
3141e51346jkim#ifdef HAVE_GETOPT
3151e51346jkim    int ch;
3161e51346jkim
3171e51346jkim    if (argc > 0)
3181e51346jkim	myname = argv[0];
3191e51346jkim
3201e51346jkim    while ((ch = getopt(argc, argv, "Bb:dgH:ilLo:Pp:rstVvy")) != -1)
3211e51346jkim    {
3221e51346jkim	switch (ch)
3231e51346jkim	{
3241e51346jkim	case 'b':
3251e51346jkim	    file_prefix = optarg;
3261e51346jkim	    break;
3271e51346jkim	case 'H':
3281e51346jkim	    dflag = dflag2 = 1;
3291e51346jkim	    defines_file_name = optarg;
3301e51346jkim	    break;
3311e51346jkim	case 'o':
3321e51346jkim	    output_file_name = optarg;
3331e51346jkim	    break;
3341e51346jkim	case 'p':
3351e51346jkim	    symbol_prefix = optarg;
3361e51346jkim	    break;
3371e51346jkim	default:
3381e51346jkim	    setflag(ch);
3391e51346jkim	    break;
3401e51346jkim	}
3411e51346jkim    }
3421e51346jkim    if ((i = optind) < argc)
3431e51346jkim    {
3441e51346jkim	/* getopt handles "--" specially, while we handle "-" specially */
3451e51346jkim	if (!strcmp(argv[i], "-"))
3461e51346jkim	{
3471e51346jkim	    if ((i + 1) < argc)
3481e51346jkim		usage();
3491e51346jkim	    input_file = stdin;
3501e51346jkim	    return;
3511e51346jkim	}
3521e51346jkim    }
3531e51346jkim#else
35426a93febapt    char *s;
35526a93febapt    int ch;
35626a93febapt
35726a93febapt    if (argc > 0)
35826a93febapt	myname = argv[0];
35926a93febapt
36026a93febapt    for (i = 1; i < argc; ++i)
36126a93febapt    {
36226a93febapt	s = argv[i];
36326a93febapt	if (*s != '-')
36426a93febapt	    break;
36526a93febapt	switch (ch = *++s)
36626a93febapt	{
36726a93febapt	case '\0':
36826a93febapt	    input_file = stdin;
36926a93febapt	    if (i + 1 < argc)
37026a93febapt		usage();
37126a93febapt	    return;
37226a93febapt
37326a93febapt	case '-':
37426a93febapt	    ++i;
37526a93febapt	    goto no_more_options;
37626a93febapt
37726a93febapt	case 'b':
37826a93febapt	    if (*++s)
37926a93febapt		file_prefix = s;
38026a93febapt	    else if (++i < argc)
38126a93febapt		file_prefix = argv[i];
38226a93febapt	    else
38326a93febapt		usage();
38426a93febapt	    continue;
38526a93febapt
3861e51346jkim	case 'H':
3871e51346jkim	    dflag = dflag2 = 1;
3881e51346jkim	    if (*++s)
3891e51346jkim		defines_file_name = s;
3901e51346jkim	    else if (++i < argc)
3911e51346jkim		defines_file_name = argv[i];
3921e51346jkim	    else
3931e51346jkim		usage();
3941e51346jkim	    continue;
3951e51346jkim
39626a93febapt	case 'o':
39726a93febapt	    if (*++s)
39826a93febapt		output_file_name = s;
39926a93febapt	    else if (++i < argc)
40026a93febapt		output_file_name = argv[i];
40126a93febapt	    else
40226a93febapt		usage();
40326a93febapt	    continue;
40426a93febapt
40526a93febapt	case 'p':
40626a93febapt	    if (*++s)
40726a93febapt		symbol_prefix = s;
40826a93febapt	    else if (++i < argc)
40926a93febapt		symbol_prefix = argv[i];
41026a93febapt	    else
41126a93febapt		usage();
41226a93febapt	    continue;
41326a93febapt
41426a93febapt	default:
41526a93febapt	    setflag(ch);
41626a93febapt	    break;
41726a93febapt	}
41826a93febapt
41926a93febapt	for (;;)
42026a93febapt	{
42126a93febapt	    switch (ch = *++s)
42226a93febapt	    {
42326a93febapt	    case '\0':
42426a93febapt		goto end_of_option;
42526a93febapt
42626a93febapt	    default:
42726a93febapt		setflag(ch);
42826a93febapt		break;
42926a93febapt	    }
43026a93febapt	}
43126a93febapt      end_of_option:;
43226a93febapt    }
43326a93febapt
4341e51346jkim  no_more_options:
4351e51346jkim
4361e51346jkim#endif /* HAVE_GETOPT */
43726a93febapt    if (i + 1 != argc)
43826a93febapt	usage();
439e7d342bjkim    input_file_name_len = strlen(argv[i]);
440e7d342bjkim    input_file_name = TMALLOC(char, input_file_name_len + 1);
441e7d342bjkim    NO_SPACE(input_file_name);
442e7d342bjkim    strcpy(input_file_name, argv[i]);
44326a93febapt}
44426a93febapt
44526a93febaptvoid *
44626a93febaptallocate(size_t n)
44726a93febapt{
44826a93febapt    void *p;
44926a93febapt
45026a93febapt    p = NULL;
45126a93febapt    if (n)
45226a93febapt    {
45326a93febapt	p = CALLOC(1, n);
45426a93febapt	NO_SPACE(p);
45526a93febapt    }
45626a93febapt    return (p);
45726a93febapt}
45826a93febapt
45926a93febapt#define CREATE_FILE_NAME(dest, suffix) \
4603c84e00bapt	dest = alloc_file_name(len, suffix)
4613c84e00bapt
4623c84e00baptstatic char *
4633c84e00baptalloc_file_name(size_t len, const char *suffix)
4643c84e00bapt{
4653c84e00bapt    char *result = TMALLOC(char, len + strlen(suffix) + 1);
4663c84e00bapt    if (result == 0)
4673c84e00bapt	no_space();
4683c84e00bapt    strcpy(result, file_prefix);
4693c84e00bapt    strcpy(result + len, suffix);
4703c84e00bapt    return result;
4713c84e00bapt}
47226a93febapt
47336f7fe3jkimstatic char *
47436f7fe3jkimfind_suffix(char *name, const char *suffix)
47536f7fe3jkim{
47636f7fe3jkim    size_t len = strlen(name);
47736f7fe3jkim    size_t slen = strlen(suffix);
47836f7fe3jkim    if (len >= slen)
47936f7fe3jkim    {
48036f7fe3jkim	name += len - slen;
48136f7fe3jkim	if (strcmp(name, suffix) == 0)
48236f7fe3jkim	    return name;
48336f7fe3jkim    }
48436f7fe3jkim    return NULL;
48536f7fe3jkim}
48636f7fe3jkim
48726a93febaptstatic void
48826a93febaptcreate_file_names(void)
48926a93febapt{
49026a93febapt    size_t len;
49126a93febapt    const char *defines_suffix;
49226a93febapt    const char *externs_suffix;
49336f7fe3jkim    char *suffix;
49426a93febapt
49536f7fe3jkim    suffix = NULL;
49626a93febapt    defines_suffix = DEFINES_SUFFIX;
49726a93febapt    externs_suffix = EXTERNS_SUFFIX;
49826a93febapt
49926a93febapt    /* compute the file_prefix from the user provided output_file_name */
50026a93febapt    if (output_file_name != 0)
50126a93febapt    {
50236f7fe3jkim	if (!(suffix = find_suffix(output_file_name, OUTPUT_SUFFIX))
50336f7fe3jkim	    && (suffix = find_suffix(output_file_name, ".c")))
50426a93febapt	{
50526a93febapt	    defines_suffix = ".h";
50626a93febapt	    externs_suffix = ".i";
50726a93febapt	}
50826a93febapt    }
50926a93febapt
51036f7fe3jkim    if (suffix != NULL)
51126a93febapt    {
51236f7fe3jkim	len = (size_t) (suffix - output_file_name);
51337c437fbapt	file_prefix = TMALLOC(char, len + 1);
51426a93febapt	NO_SPACE(file_prefix);
51526a93febapt	strncpy(file_prefix, output_file_name, len)[len] = 0;
51626a93febapt    }
51726a93febapt    else
51826a93febapt	len = strlen(file_prefix);
51926a93febapt
52026a93febapt    /* if "-o filename" was not given */
52126a93febapt    if (output_file_name == 0)
52226a93febapt    {
52326a93febapt	oflag = 1;
52426a93febapt	CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX);
52526a93febapt    }
52626a93febapt
52726a93febapt    if (rflag)
52826a93febapt    {
52926a93febapt	CREATE_FILE_NAME(code_file_name, CODE_SUFFIX);
53026a93febapt    }
53126a93febapt    else
53226a93febapt	code_file_name = output_file_name;
53326a93febapt
5341e51346jkim    if (dflag && !dflag2)
53526a93febapt    {
53626a93febapt	CREATE_FILE_NAME(defines_file_name, defines_suffix);
53726a93febapt    }
53826a93febapt
53926a93febapt    if (iflag)
54026a93febapt    {
54126a93febapt	CREATE_FILE_NAME(externs_file_name, externs_suffix);
54226a93febapt    }
54326a93febapt
54426a93febapt    if (vflag)
54526a93febapt    {
54626a93febapt	CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX);
54726a93febapt    }
54826a93febapt
54926a93febapt    if (gflag)
55026a93febapt    {
55126a93febapt	CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX);
55226a93febapt    }
55326a93febapt
55436f7fe3jkim    if (suffix != NULL)
55526a93febapt    {
55626a93febapt	FREE(file_prefix);
55726a93febapt    }
55826a93febapt}
55926a93febapt
56026a93febapt#if USE_MKSTEMP
56126a93febaptstatic void
56226a93febaptclose_tmpfiles(void)
56326a93febapt{
56426a93febapt    while (my_tmpfiles != 0)
56526a93febapt    {
56626a93febapt	MY_TMPFILES *next = my_tmpfiles->next;
56726a93febapt
5683090913bapt	(void)chmod(my_tmpfiles->name, 0644);
5693090913bapt	(void)unlink(my_tmpfiles->name);
57026a93febapt
57126a93febapt	free(my_tmpfiles->name);
57226a93febapt	free(my_tmpfiles);
57326a93febapt
57426a93febapt	my_tmpfiles = next;
57526a93febapt    }
57626a93febapt}
57726a93febapt
57826a93febapt#ifndef HAVE_MKSTEMP
57926a93febaptstatic int
58026a93febaptmy_mkstemp(char *temp)
58126a93febapt{
58226a93febapt    int fd;
58326a93febapt    char *dname;
58426a93febapt    char *fname;
58526a93febapt    char *name;
58626a93febapt
58726a93febapt    /*
58826a93febapt     * Split-up to use tempnam, rather than tmpnam; the latter (like
58926a93febapt     * mkstemp) is unusable on Windows.
59026a93febapt     */
59126a93febapt    if ((fname = strrchr(temp, '/')) != 0)
59226a93febapt    {
59326a93febapt	dname = strdup(temp);
59426a93febapt	dname[++fname - temp] = '\0';
59526a93febapt    }
59626a93febapt    else
59726a93febapt    {
59826a93febapt	dname = 0;
59926a93febapt	fname = temp;
60026a93febapt    }
60126a93febapt    if ((name = tempnam(dname, fname)) != 0)
60226a93febapt    {
60326a93febapt	fd = open(name, O_CREAT | O_EXCL | O_RDWR);
60426a93febapt	strcpy(temp, name);
60526a93febapt    }
60626a93febapt    else
60726a93febapt    {
60826a93febapt	fd = -1;
60926a93febapt    }
61026a93febapt
61126a93febapt    if (dname != 0)
61226a93febapt	free(dname);
61326a93febapt
61426a93febapt    return fd;
61526a93febapt}
61626a93febapt#define mkstemp(s) my_mkstemp(s)
61726a93febapt#endif
61826a93febapt
61926a93febapt#endif
62026a93febapt
62126a93febapt/*
62226a93febapt * tmpfile() should be adequate, except that it may require special privileges
62326a93febapt * to use, e.g., MinGW and Windows 7 where it tries to use the root directory.
62426a93febapt */
62526a93febaptstatic FILE *
62626a93febaptopen_tmpfile(const char *label)
62726a93febapt{
6280ea517cjkim#define MY_FMT "%s/%.*sXXXXXX"
62926a93febapt    FILE *result;
63026a93febapt#if USE_MKSTEMP
63126a93febapt    int fd;
63226a93febapt    const char *tmpdir;
63326a93febapt    char *name;
63426a93febapt    const char *mark;
63526a93febapt
6361e51346jkim    if (((tmpdir = getenv("TMPDIR")) == 0 || access(tmpdir, W_OK) != 0) ||
6371e51346jkim	((tmpdir = getenv("TEMP")) == 0 || access(tmpdir, W_OK) != 0))
63826a93febapt    {
63926a93febapt#ifdef P_tmpdir
64026a93febapt	tmpdir = P_tmpdir;
64126a93febapt#else
64226a93febapt	tmpdir = "/tmp";
64326a93febapt#endif
64426a93febapt	if (access(tmpdir, W_OK) != 0)
64526a93febapt	    tmpdir = ".";
64626a93febapt    }
64726a93febapt
6480ea517cjkim    /* The size of the format is guaranteed to be longer than the result from
6490ea517cjkim     * printing empty strings with it; this calculation accounts for the
6500ea517cjkim     * string-lengths as well.
6510ea517cjkim     */
6520ea517cjkim    name = malloc(strlen(tmpdir) + sizeof(MY_FMT) + strlen(label));
65326a93febapt
65426a93febapt    result = 0;
65526a93febapt    if (name != 0)
65626a93febapt    {
65786771febapt	mode_t save_umask = umask(0177);
6583090913bapt
65926a93febapt	if ((mark = strrchr(label, '_')) == 0)
66026a93febapt	    mark = label + strlen(label);
66126a93febapt
6620ea517cjkim	sprintf(name, MY_FMT, tmpdir, (int)(mark - label), label);
66326a93febapt	fd = mkstemp(name);
6641e51346jkim	if (fd >= 0
6651e51346jkim	    && (result = fdopen(fd, "w+")) != 0)
66626a93febapt	{
6671e51346jkim	    MY_TMPFILES *item;
66826a93febapt
6691e51346jkim	    if (my_tmpfiles == 0)
6701e51346jkim	    {
6711e51346jkim		atexit(close_tmpfiles);
6721e51346jkim	    }
67326a93febapt
6741e51346jkim	    item = NEW(MY_TMPFILES);
6751e51346jkim	    NO_SPACE(item);
67626a93febapt
6771e51346jkim	    item->name = name;
6781e51346jkim	    NO_SPACE(item->name);
67926a93febapt
6801e51346jkim	    item->next = my_tmpfiles;
6811e51346jkim	    my_tmpfiles = item;
6821e51346jkim	}
6831e51346jkim	else
6841e51346jkim	{
6851e51346jkim	    FREE(name);
68626a93febapt	}
6873090913bapt	(void)umask(save_umask);
68826a93febapt    }
68926a93febapt#else
69026a93febapt    result = tmpfile();
69126a93febapt#endif
69226a93febapt
69326a93febapt    if (result == 0)
69426a93febapt	open_error(label);
69526a93febapt    return result;
6960ea517cjkim#undef MY_FMT
69726a93febapt}
69826a93febapt
69926a93febaptstatic void
70026a93febaptopen_files(void)
70126a93febapt{
70226a93febapt    create_file_names();
70326a93febapt
70426a93febapt    if (input_file == 0)
70526a93febapt    {
70626a93febapt	input_file = fopen(input_file_name, "r");
70726a93febapt	if (input_file == 0)
70826a93febapt	    open_error(input_file_name);
70926a93febapt    }
71026a93febapt
71126a93febapt    action_file = open_tmpfile("action_file");
71226a93febapt    text_file = open_tmpfile("text_file");
71326a93febapt
71426a93febapt    if (vflag)
71526a93febapt    {
71626a93febapt	verbose_file = fopen(verbose_file_name, "w");
71726a93febapt	if (verbose_file == 0)
71826a93febapt	    open_error(verbose_file_name);
71926a93febapt    }
72026a93febapt
72126a93febapt    if (gflag)
72226a93febapt    {
72326a93febapt	graph_file = fopen(graph_file_name, "w");
72426a93febapt	if (graph_file == 0)
72526a93febapt	    open_error(graph_file_name);
72626a93febapt	fprintf(graph_file, "digraph %s {\n", file_prefix);
72726a93febapt	fprintf(graph_file, "\tedge [fontsize=10];\n");
72826a93febapt	fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n");
72926a93febapt	fprintf(graph_file, "\torientation=landscape;\n");
73026a93febapt	fprintf(graph_file, "\trankdir=LR;\n");
73126a93febapt	fprintf(graph_file, "\t/*\n");
73226a93febapt	fprintf(graph_file, "\tmargin=0.2;\n");
73326a93febapt	fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n");
73426a93febapt	fprintf(graph_file, "\tratio=auto;\n");
73526a93febapt	fprintf(graph_file, "\t*/\n");
73626a93febapt    }
73726a93febapt
7381e51346jkim    if (dflag || dflag2)
73926a93febapt    {
74026a93febapt	defines_file = fopen(defines_file_name, "w");
74126a93febapt	if (defines_file == 0)
74226a93febapt	    open_error(defines_file_name);
74326a93febapt	union_file = open_tmpfile("union_file");
74426a93febapt    }
74526a93febapt
74626a93febapt    if (iflag)
74726a93febapt    {
74826a93febapt	externs_file = fopen(externs_file_name, "w");
74926a93febapt	if (externs_file == 0)
75026a93febapt	    open_error(externs_file_name);
75126a93febapt    }
75226a93febapt
75326a93febapt    output_file = fopen(output_file_name, "w");
75426a93febapt    if (output_file == 0)
75526a93febapt	open_error(output_file_name);
75626a93febapt
75726a93febapt    if (rflag)
75826a93febapt    {
75926a93febapt	code_file = fopen(code_file_name, "w");
76026a93febapt	if (code_file == 0)
76126a93febapt	    open_error(code_file_name);
76226a93febapt    }
76326a93febapt    else
76426a93febapt	code_file = output_file;
76526a93febapt}
76626a93febapt
76726a93febaptint
76826a93febaptmain(int argc, char *argv[])
76926a93febapt{
77026a93febapt    SRexpect = -1;
77126a93febapt    RRexpect = -1;
77226a93febapt    exit_code = EXIT_SUCCESS;
77326a93febapt
77426a93febapt    set_signals();
77526a93febapt    getargs(argc, argv);
77626a93febapt    open_files();
77726a93febapt    reader();
77826a93febapt    lr0();
77926a93febapt    lalr();
78026a93febapt    make_parser();
78126a93febapt    graph();
78226a93febapt    finalize_closure();
78326a93febapt    verbose();
78426a93febapt    output();
78526a93febapt    done(exit_code);
78626a93febapt    /*NOTREACHED */
78726a93febapt}
788