Esempio n. 1
0
/** Splits the chain in order to write to a header file.
 *  Similar in spirit to the 'tee' program.
 *  The header file name is in extra.
 *  @return 0 (zero) on success, and -1 on failure.
 */
int filter_tee_header (struct filter *chain)
{
	/* This function reads from stdin and writes to both the C file and the
	 * header file at the same time.
	 */

	const int readsz = 512;
	char   *buf;
	int     to_cfd = -1;
	FILE   *to_c = NULL, *to_h = NULL;
	bool    write_header;

	write_header = (chain->extra != NULL);

	/* Store a copy of the stdout pipe, which is already piped to C file
	 * through the running chain. Then create a new pipe to the H file as
	 * stdout, and fork the rest of the chain again.
	 */

	if ((to_cfd = dup (1)) == -1)
		flexfatal (_("dup(1) failed"));
	to_c = fdopen (to_cfd, "w");

	if (write_header) {
		if (freopen ((char *) chain->extra, "w", stdout) == NULL)
			flexfatal (_("freopen(headerfilename) failed"));

		filter_apply_chain (chain->next);
		to_h = stdout;
	}

	/* Now to_c is a pipe to the C branch, and to_h is a pipe to the H branch.
	 */

	if (write_header) {
        fputs (check_4_gnu_m4, to_h);
		fputs ("m4_changecom`'m4_dnl\n", to_h);
		fputs ("m4_changequote`'m4_dnl\n", to_h);
		fputs ("m4_changequote([[,]])[[]]m4_dnl\n", to_h);
	    fputs ("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", to_h);
		fputs ("m4_define( [[M4_YY_IN_HEADER]],[[]])m4_dnl\n",
		       to_h);
		fprintf (to_h, "#ifndef %sHEADER_H\n", prefix);
		fprintf (to_h, "#define %sHEADER_H 1\n", prefix);
		fprintf (to_h, "#define %sIN_HEADER 1\n\n", prefix);
		fprintf (to_h,
			 "m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n",
			 headerfilename ? headerfilename : "<stdout>");

	}

    fputs (check_4_gnu_m4, to_c);
	fputs ("m4_changecom`'m4_dnl\n", to_c);
	fputs ("m4_changequote`'m4_dnl\n", to_c);
	fputs ("m4_changequote([[,]])[[]]m4_dnl\n", to_c);
	fputs ("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", to_c);
	fprintf (to_c, "m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n",
		 outfilename ? outfilename : "<stdout>");

	buf = malloc(readsz);
	if (!buf)
		flexerror(_("malloc failed in filter_tee_header"));
	while (fgets (buf, readsz, stdin)) {
		fputs (buf, to_c);
		if (write_header)
			fputs (buf, to_h);
	}

	if (write_header) {
		fprintf (to_h, "\n");

		/* write a fake line number. It will get fixed by the linedir filter. */
		fprintf (to_h, "#line 4000 \"M4_YY_OUTFILE_NAME\"\n");

		fprintf (to_h, "#undef %sIN_HEADER\n", prefix);
		fprintf (to_h, "#endif /* %sHEADER_H */\n", prefix);
		fputs ("m4_undefine( [[M4_YY_IN_HEADER]])m4_dnl\n", to_h);

		fflush (to_h);
		if (ferror (to_h))
			lerr (_("error writing output file %s"),
				(char *) chain->extra);

		else if (fclose (to_h))
			lerr (_("error closing output file %s"),
				(char *) chain->extra);
	}

	fflush (to_c);
	if (ferror (to_c))
		lerr (_("error writing output file %s"),
			outfilename ? outfilename : "<stdout>");

	else if (fclose (to_c))
		lerr (_("error closing output file %s"),
			outfilename ? outfilename : "<stdout>");

	while (wait (0) > 0) ;

	exit (0);
	return 0;
}
Esempio n. 2
0
/** Fork and exec entire filter chain.
 *  @param chain The head of the chain.
 *  @return true on success.
 */
bool 
filter_apply_chain(struct filter * chain)
{
	int pid, pipes[2];
	int r;
	const int readsz = 512;
	char *buf;


	/*
	 * Tricky recursion, since we want to begin the chain at the END.
	 * Why? Because we need all the forked processes to be children of
	 * the main flex process.
	 */
	if (chain)
		filter_apply_chain(chain->next);
	else
		return true;

	/*
	 * Now we are the right-most unprocessed link in the chain.
	 */

	fflush(stdout);
	fflush(stderr);


	if (pipe(pipes) == -1)
		flexerror(_("pipe failed"));

	if ((pid = fork()) == -1)
		flexerror(_("fork failed"));

	if (pid == 0) {
		/* child */

		/*
		 * We need stdin (the FILE* stdin) to connect to this new
		 * pipe. There is no portable way to set stdin to a new file
		 * descriptor, as stdin is not an lvalue on some systems
		 * (BSD). So we dup the new pipe onto the stdin descriptor
		 * and use a no-op fseek to sync the stream. This is a Hail
		 * Mary situation. It seems to work.
		 */
		close(pipes[1]);
		clearerr(stdin);
		if (dup2(pipes[0], fileno(stdin)) == -1)
			flexfatal(_("dup2(pipes[0],0)"));
		close(pipes[0]);
		fseek(stdin, 0, SEEK_CUR);

		/* run as a filter, either internally or by exec */
		if (chain->filter_func) {
			int r;

			if ((r = chain->filter_func(chain)) == -1)
				flexfatal(_("filter_func failed"));
			exit(0);
		} else {
			execvp(chain->argv[0],
			    (char **const) (chain->argv));
			lerrsf_fatal(_("exec of %s failed"),
			    chain->argv[0]);
		}

		exit(1);
	}
	/* Parent */
	close(pipes[0]);
	if (dup2(pipes[1], fileno(stdout)) == -1)
		flexfatal(_("dup2(pipes[1],1)"));
	close(pipes[1]);
	fseek(stdout, 0, SEEK_CUR);

	return true;
}
Esempio n. 3
0
/** Fork and exec entire filter chain.
 *  @param chain The head of the chain.
 *  @return true on success.
 */
bool filter_apply_chain (struct filter * chain)
{
	int     pid, pipes[2];


	/* Tricky recursion, since we want to begin the chain
	 * at the END. Why? Because we need all the forked processes
	 * to be children of the main flex process.
	 */
	if (chain)
		filter_apply_chain (chain->next);
	else
		return true;

	/* Now we are the right-most unprocessed link in the chain.
	 */

	fflush (stdout);
	fflush (stderr);


	if (pipe (pipes) == -1)
		flexerror (_("pipe failed"));

	if ((pid = fork ()) == -1)
		flexerror (_("fork failed"));

	if (pid == 0) {
		/* child */

        /* We need stdin (the FILE* stdin) to connect to this new pipe.
         * There is no portable way to set stdin to a new file descriptor,
         * as stdin is not an lvalue on some systems (BSD).
         * So we dup the new pipe onto the stdin descriptor and use a no-op fseek
         * to sync the stream. This is a Hail Mary situation. It seems to work.
         */
		close (pipes[1]);
clearerr(stdin);
		if (dup2 (pipes[0], fileno (stdin)) == -1)
			flexfatal (_("dup2(pipes[0],0)"));
		close (pipes[0]);
        fseek (stdin, 0, SEEK_CUR);
        ungetc(' ', stdin); /* still an evil hack, but one that works better */
        (void)fgetc(stdin); /* on NetBSD than the fseek attempt does */

		/* run as a filter, either internally or by exec */
		if (chain->filter_func) {
			int     r;

			if ((r = chain->filter_func (chain)) == -1)
				flexfatal (_("filter_func failed"));
			exit (0);
		}
		else {
			execvp (chain->argv[0],
				(char **const) (chain->argv));
            lerr_fatal ( _("exec of %s failed"),
                    chain->argv[0]);
		}

		exit (1);
	}

	/* Parent */
	close (pipes[0]);
	if (dup2 (pipes[1], fileno (stdout)) == -1)
		flexfatal (_("dup2(pipes[1],1)"));
	close (pipes[1]);
    fseek (stdout, 0, SEEK_CUR);

	return true;
}
Esempio n. 4
0
void check_options (void)
{
	int     i;
    const char * m4 = NULL;

	if (lex_compat) {
		if (C_plus_plus)
			flexerror (_("Can't use -+ with -l option"));

		if (fulltbl || fullspd)
			flexerror (_("Can't use -f or -F with -l option"));

		if (reentrant || bison_bridge_lval)
			flexerror (_
				   ("Can't use --reentrant or --bison-bridge with -l option"));

		yytext_is_array = true;
		do_yylineno = true;
		use_read = false;
	}


#if 0
	/* This makes no sense whatsoever. I'm removing it. */
	if (do_yylineno)
		/* This should really be "maintain_backup_tables = true" */
		reject_really_used = true;
#endif

	if (csize == unspecified) {
		if ((fulltbl || fullspd) && !useecs)
			csize = DEFAULT_CSIZE;
		else
			csize = CSIZE;
	}

	if (interactive == unspecified) {
		if (fulltbl || fullspd)
			interactive = false;
		else
			interactive = true;
	}

	if (fulltbl || fullspd) {
		if (usemecs)
			flexerror (_
				   ("-Cf/-CF and -Cm don't make sense together"));

		if (interactive)
			flexerror (_("-Cf/-CF and -I are incompatible"));

		if (lex_compat)
			flexerror (_
				   ("-Cf/-CF are incompatible with lex-compatibility mode"));


		if (fulltbl && fullspd)
			flexerror (_
				   ("-Cf and -CF are mutually exclusive"));
	}

	if (C_plus_plus && fullspd)
		flexerror (_("Can't use -+ with -CF option"));

	if (C_plus_plus && yytext_is_array) {
		lwarn (_("%array incompatible with -+ option"));
		yytext_is_array = false;
	}

	if (C_plus_plus && (reentrant))
		flexerror (_("Options -+ and --reentrant are mutually exclusive."));

	if (C_plus_plus && bison_bridge_lval)
		flexerror (_("bison bridge not supported for the C++ scanner."));


	if (useecs) {		/* Set up doubly-linked equivalence classes. */

		/* We loop all the way up to csize, since ecgroup[csize] is
		 * the position used for NUL characters.
		 */
		ecgroup[1] = NIL;

		for (i = 2; i <= csize; ++i) {
			ecgroup[i] = i - 1;
			nextecm[i - 1] = i;
		}

		nextecm[csize] = NIL;
	}

	else {
		/* Put everything in its own equivalence class. */
		for (i = 1; i <= csize; ++i) {
			ecgroup[i] = i;
			nextecm[i] = BAD_SUBSCRIPT;	/* to catch errors */
		}
	}

    if (extra_type)
        buf_m4_define( &m4defs_buf, "M4_EXTRA_TYPE_DEFS", extra_type);

	if (!use_stdout) {
		FILE   *prev_stdout;

		if (!did_outfilename) {
			char   *suffix;

			if (C_plus_plus)
				suffix = "cc";
			else
				suffix = "c";

			snprintf (outfile_path, sizeof(outfile_path), outfile_template,
				 prefix, suffix);

			outfilename = outfile_path;
		}

		prev_stdout = freopen (outfilename, "w+", stdout);

		if (prev_stdout == NULL)
			lerr (_("could not create %s"), outfilename);

		outfile_created = 1;
	}


    /* Setup the filter chain. */
    output_chain = filter_create_int(NULL, filter_tee_header, headerfilename);
    if ( !(m4 = getenv("M4"))) {
	    char *slash;
		m4 = M4;
		if ((slash = strrchr(M4, '/')) != NULL) {
			m4 = slash+1;
			/* break up $PATH */
			const char *path = getenv("PATH");
			if (!path) {
				m4 = M4;
			} else {
				int m4_length = strlen(m4);
				do {
					size_t length = strlen(path);
					struct stat sbuf;

					const char *endOfDir = strchr(path, ':');
					if (!endOfDir)
						endOfDir = path+length;

					{
						char *m4_path = calloc(endOfDir-path + 1 + m4_length + 1, 1);

						memcpy(m4_path, path, endOfDir-path);
						m4_path[endOfDir-path] = '/';
						memcpy(m4_path + (endOfDir-path) + 1, m4, m4_length + 1);
						if (stat(m4_path, &sbuf) == 0 &&
							(S_ISREG(sbuf.st_mode)) && sbuf.st_mode & S_IXUSR) {
							m4 = m4_path;
							break;
						}
						free(m4_path);
					}
					path = endOfDir+1;
				} while (path[0]);
				if (!path[0])
				    m4 = M4;
			}
		}
	}
    filter_create_ext(output_chain, m4, "-P", 0);
    filter_create_int(output_chain, filter_fix_linedirs, NULL);

    /* For debugging, only run the requested number of filters. */
    if (preproc_level > 0) {
        filter_truncate(output_chain, preproc_level);
        filter_apply_chain(output_chain);
    }
    yyout = stdout;


	/* always generate the tablesverify flag. */
	buf_m4_define (&m4defs_buf, "M4_YY_TABLES_VERIFY", tablesverify ? "1" : "0");
	if (tablesext)
		gentables = false;

	if (tablesverify)
		/* force generation of C tables. */
		gentables = true;


	if (tablesext) {
		FILE   *tablesout;
		struct yytbl_hdr hdr;
		char   *pname = 0;
		size_t  nbytes = 0;

		buf_m4_define (&m4defs_buf, "M4_YY_TABLES_EXTERNAL", NULL);

		if (!tablesfilename) {
			nbytes = strlen (prefix) + strlen (tablesfile_template) + 2;
			tablesfilename = pname = calloc(nbytes, 1);
			snprintf (pname, nbytes, tablesfile_template, prefix);
		}

		if ((tablesout = fopen (tablesfilename, "w")) == NULL)
			lerr (_("could not create %s"), tablesfilename);
		free(pname);
		tablesfilename = 0;

		yytbl_writer_init (&tableswr, tablesout);

		nbytes = strlen (prefix) + strlen ("tables") + 2;
		tablesname = calloc(nbytes, 1);
		snprintf (tablesname, nbytes, "%stables", prefix);
		yytbl_hdr_init (&hdr, flex_version, tablesname);

		if (yytbl_hdr_fwrite (&tableswr, &hdr) <= 0)
			flexerror (_("could not write tables header"));
	}

	if (skelname && (skelfile = fopen (skelname, "r")) == NULL)
		lerr (_("can't open skeleton file %s"), skelname);

	if (reentrant) {
        buf_m4_define (&m4defs_buf, "M4_YY_REENTRANT", NULL);
		if (yytext_is_array)
			buf_m4_define (&m4defs_buf, "M4_YY_TEXT_IS_ARRAY", NULL);
	}

	if ( bison_bridge_lval)
		buf_m4_define (&m4defs_buf, "M4_YY_BISON_LVAL", NULL);

	if ( bison_bridge_lloc)
        buf_m4_define (&m4defs_buf, "<M4_YY_BISON_LLOC>", NULL);

    if (strchr(prefix, '[') || strchr(prefix, ']'))
        flexerror(_("Prefix cannot include '[' or ']'"));
    buf_m4_define(&m4defs_buf, "M4_YY_PREFIX", prefix);

	if (did_outfilename)
		line_directive_out (stdout, 0);

	if (do_yylineno)
		buf_m4_define (&m4defs_buf, "M4_YY_USE_LINENO", NULL);

	/* Create the alignment type. */
	buf_strdefine (&userdef_buf, "YY_INT_ALIGNED",
		       long_align ? "long int" : "short int");

    /* Define the start condition macros. */
    {
        struct Buf tmpbuf;
        buf_init(&tmpbuf, sizeof(char));
        for (i = 1; i <= lastsc; i++) {
             char *str, *fmt = "#define %s %d\n";
             size_t strsz;

             strsz = strlen(fmt) + strlen(scname[i]) + (size_t)(1 + ceil (log10(i))) + 2;
             str = malloc(strsz);
             if (!str)
               flexfatal(_("allocation of macro definition failed"));
             snprintf(str, strsz, fmt,      scname[i], i - 1);
             buf_strappend(&tmpbuf, str);
             free(str);
        }
        buf_m4_define(&m4defs_buf, "M4_YY_SC_DEFS", tmpbuf.elts);
        buf_destroy(&tmpbuf);
    }

    /* This is where we begin writing to the file. */

    /* Dump the %top code. */
    if( top_buf.elts)
        outn((char*) top_buf.elts);

    /* Dump the m4 definitions. */
    buf_print_strings(&m4defs_buf, stdout);
    m4defs_buf.nelts = 0; /* memory leak here. */

    /* Place a bogus line directive, it will be fixed in the filter. */
    if (gen_line_dirs)
        outn("#line 0 \"M4_YY_OUTFILE_NAME\"\n");

	/* Dump the user defined preproc directives. */
	if (userdef_buf.elts)
		outn ((char *) (userdef_buf.elts));

	skelout ();
	/* %% [1.0] */
}