int dupmachine(int mach) { int i, init, state_offset; int state = 0; int last = lastst[mach]; for ( i = firstst[mach]; i <= last; ++i ) { state = mkstate( transchar[i] ); if ( trans1[i] != NO_TRANSITION ) { mkxtion( finalst[state], trans1[i] + state - i ); if ( transchar[i] == SYM_EPSILON && trans2[i] != NO_TRANSITION ) mkxtion( finalst[state], trans2[i] + state - i ); } accptnum[state] = accptnum[i]; } if ( state == 0 ) flexfatal( "empty machine in dupmachine()" ); state_offset = state - i + 1; init = mach + state_offset; firstst[init] = firstst[mach] + state_offset; finalst[init] = finalst[mach] + state_offset; lastst[init] = lastst[mach] + state_offset; return ( init ); }
/* copy_string - returns a dynamically allocated copy of a string */ char * copy_string(const char *str) { const char *c1; char *c2; char *copy; size_t size; /* find length */ for (c1 = str; *c1; ++c1) { ; } size = (unsigned) (c1 - str + 1) * sizeof(char); copy = (char *) flex_alloc(size); if (copy == NULL) flexfatal(_("dynamic memory failure in copy_string()")); assert(copy != NULL); for (c2 = copy; (*c2++ = *str++) != 0;) { ; } return copy; }
/** Append a line directive to the string buffer. * @param buf A string buffer. * @param filename file name * @param lineno line number * @return buf */ struct Buf * buf_linedir(struct Buf * buf, const char *filename, int lineno) { const char *src; char *dst, *t; size_t tsz; tsz = strlen("#line \"\"\n") + /* constant parts */ 2 * strlen(filename) + /* filename with possibly all backslashes escaped */ (int) (1 + log10(abs(lineno))) + /* line number */ 1; /* NUL */ t = malloc(tsz); if (!t) flexfatal(_("Allocation of buffer for line directive failed")); dst = t + snprintf(t, tsz, "#line %d \"", lineno); for (src = filename; *src; *dst++ = *src++) if (*src == '\\') /* escape backslashes */ *dst++ = '\\'; *dst++ = '"'; *dst++ = '\n'; *dst = '\0'; buf = buf_strappend(buf, t); free(t); return buf; }
char *xstrdup(const char *s) { char *s2; if ((s2 = strdup(s)) == NULL) flexfatal (_("memory allocation failure in xstrdup()")); return s2; }
/* The following is only needed when building flex's parser using certain * broken versions of bison. */ void *yy_flex_xmalloc(int size) { void *result = flex_alloc( (size_t) size ); if ( ! result ) flexfatal( _( "memory allocation failed in yy_flex_xmalloc()" ) ); return result; }
void lerr_fatal (const char *msg, ...) { char errmsg[MAXLINE]; va_list args; va_start(args, msg); vsnprintf (errmsg, sizeof(errmsg), msg, args); va_end(args); flexfatal (errmsg); }
void *reallocate_array(void *array, int size, size_t element_size) { void *new_array; size_t num_bytes = element_size * size; new_array = flex_realloc( array, num_bytes ); if ( ! new_array ) flexfatal( _( "attempt to increase array size failed" ) ); return new_array; }
void *allocate_array (int size, size_t element_size) { void *new_array; #if HAVE_REALLOCARR new_array = NULL; if (reallocarr(&new_array, (size_t) size, element_size)) flexfatal (_("memory allocation failed in allocate_array()")); #else # if HAVE_REALLOCARRAY new_array = reallocarray(NULL, (size_t) size, element_size); # else /* Do manual overflow detection */ size_t num_bytes = (size_t) size * element_size; new_array = (size && SIZE_MAX / (size_t) size < element_size) ? NULL : malloc(num_bytes); # endif if (!new_array) flexfatal (_("memory allocation failed in allocate_array()")); #endif return new_array; }
void *reallocate_array (void *array, int size, size_t element_size) { void *new_array; #if HAVE_REALLOCARR new_array = array; if (reallocarr(&new_array, (size_t) size, element_size)) flexfatal (_("attempt to increase array size failed")); #else # if HAVE_REALLOCARRAY new_array = reallocarray(array, (size_t) size, element_size); # else /* Do manual overflow detection */ size_t num_bytes = (size_t) size * element_size; new_array = (size && SIZE_MAX / (size_t) size < element_size) ? NULL : realloc(array, num_bytes); # endif if (!new_array) flexfatal (_("attempt to increase array size failed")); #endif return new_array; }
void *allocate_array(int size, size_t element_size) { void *mem; size_t num_bytes = element_size * size; mem = flex_alloc( num_bytes ); if ( ! mem ) flexfatal( _( "memory allocation failed in allocate_array()" ) ); return mem; }
/* Append a "%s" formatted string to a string buffer */ struct Buf *buf_prints (struct Buf *buf, const char *fmt, const char *s) { char *t; size_t tsz; t = flex_alloc (tsz = strlen (fmt) + strlen (s) + 1); if (!t) flexfatal (_("Allocation of buffer to print string failed")); snprintf (t, tsz, fmt, s); buf = buf_strappend (buf, t); flex_free (t); return buf; }
/** Pushes "m4_undefine([[def]])m4_dnl" to end of buffer. * @param buf A buffer as a list of strings. * @param def The m4 symbol to undefine. * @return buf */ struct Buf *buf_m4_undefine (struct Buf *buf, const char* def) { const char * fmt = "m4_undefine( [[%s]])m4_dnl\n"; char * str; size_t strsz; str = (char*)flex_alloc(strsz = strlen(fmt) + strlen(def) + 2); if (!str) flexfatal (_("Allocation of buffer for m4 undef failed")); snprintf(str, strsz, fmt, def); buf_append(buf, &str, 1); return buf; }
/* skelout - write out one section of the skeleton file * * Description * Copies skelfile or skel array to stdout until a line beginning with * "%%" or EOF is found. */ void skelout(void) { char buf_storage[MAXLINE]; char *buf = buf_storage; int do_copy = 1; /* Loop pulling lines either from the skelfile, if we're using * one, or from the skel[] array. */ while ( skelfile ? (fgets( buf, MAXLINE, skelfile ) != NULL) : ((buf = (char *) skel[skel_ind++]) != 0) ) { /* copy from skel array */ if ( buf[0] == '%' ) { /* control line */ switch ( buf[1] ) { case '%': return; case '+': do_copy = C_plus_plus; break; case '-': do_copy = ! C_plus_plus; break; case '*': do_copy = 1; break; default: flexfatal( _( "bad line in skeleton file" ) ); } } else if ( do_copy ) { if ( skelfile ) /* Skeleton file reads include final * newline, skel[] array does not. */ out( buf ); else outn( buf ); } } }
/** Extract a copy of the match, or NULL if no match. * @param m A match as returned by regexec(). * @param src The source string that was passed to regexec(). * @return The allocated string. */ char *regmatch_dup (regmatch_t * m, const char *src) { char *str; int len; if (m == NULL || m->rm_so < 0) return NULL; len = m->rm_eo - m->rm_so; str = (char *) flex_alloc ((len + 1) * sizeof (char)); if (!str) flexfatal(_("Unable to allocate a copy of the match")); strncpy (str, src + m->rm_so, len); str[len] = 0; return str; }
void mkxtion(int statefrom, int stateto) { if ( trans1[statefrom] == NO_TRANSITION ) trans1[statefrom] = stateto; else if ( (transchar[statefrom] != SYM_EPSILON) || (trans2[statefrom] != NO_TRANSITION) ) flexfatal( "found too many transitions in mkxtion()" ); else { /* second out-transition for an epsilon state */ ++eps2; trans2[statefrom] = stateto; } }
/* reallocate_array - increase the size of a dynamic array */ void * reallocate_array(void *array, long size, size_t element_size) { void *new_array = 0; if (size > 0) { size_t num_bytes = element_size * (unsigned) size; new_array = flex_realloc(array, num_bytes); } if (!new_array) flexfatal(_("attempt to increase array size failed")); return new_array; }
/** Compiles a regular expression or dies trying. * @param preg Same as for regcomp(). * @param regex Same as for regcomp(). * @param cflags Same as for regcomp(). */ void flex_regcomp(regex_t *preg, const char *regex, int cflags) { int err; memset (preg, 0, sizeof (regex_t)); if ((err = regcomp (preg, regex, cflags)) != 0) { const int errbuf_sz = 200; char *errbuf, *rxerr; errbuf = (char*)flex_alloc(errbuf_sz *sizeof(char)); if (!errbuf) flexfatal(_("Unable to allocate buffer to report regcomp")); rxerr = (char*)flex_alloc(errbuf_sz *sizeof(char)); if (!rxerr) flexfatal(_("Unable to allocate buffer for regerror")); regerror (err, preg, rxerr, errbuf_sz); snprintf (errbuf, errbuf_sz, "regcomp for \"%s\" failed: %s", regex, rxerr); flexfatal (errbuf); free(errbuf); free(rxerr); } }
/** Pushes "m4_define( [[def]], [[val]])m4_dnl" to end of buffer. * @param buf A buffer as a list of strings. * @param def The m4 symbol to define. * @param val The definition; may be NULL. * @return buf */ struct Buf *buf_m4_define (struct Buf *buf, const char* def, const char* val) { const char * fmt = "m4_define( [[%s]], [[[[%s]]]])m4_dnl\n"; char * str; size_t strsz; val = val?val:""; strsz = strlen(fmt) + strlen(def) + strlen(val) + 2; str = malloc(strsz); if (!str) flexfatal (_("Allocation of buffer for m4 def failed")); snprintf(str, strsz, fmt, def, val); buf_append(buf, &str, 1); return buf; }
static void sko_push(bool dc) { if(!sko_stack){ sko_sz = 1; sko_stack = (struct sko_state*)flex_alloc(sizeof(struct sko_state)*sko_sz); if (!sko_stack) flexfatal(_("allocation of sko_stack failed")); sko_len = 0; } if(sko_len >= sko_sz){ sko_sz *= 2; sko_stack = (struct sko_state*)flex_realloc(sko_stack,sizeof(struct sko_state)*sko_sz); } /* initialize to zero and push */ sko_stack[sko_len].dc = dc; sko_len++; }
int addsym(char *sym, char *str_def, int int_def, hash_table table, int table_size) { int hash_val = hashfunct( sym, table_size ); struct hash_entry *sym_entry = table[hash_val]; struct hash_entry *new_entry; struct hash_entry *successor; while ( sym_entry ) { if ( ! strcmp( sym, sym_entry->name ) ) { /* entry already exists */ return -1; } sym_entry = sym_entry->next; } /* create new entry */ new_entry = (struct hash_entry *) flex_alloc( sizeof( struct hash_entry ) ); if ( new_entry == NULL ) flexfatal( _( "symbol table memory allocation failed" ) ); if ( (successor = table[hash_val]) != NULL ) { new_entry->next = successor; successor->prev = new_entry; } else new_entry->next = NULL; new_entry->prev = NULL; new_entry->name = sym; new_entry->str_val = str_def; new_entry->int_val = int_def; table[hash_val] = new_entry; return 0; }
/** Append a line directive to the string buffer. * @param buf A string buffer. * @param filename file name * @param lineno line number * @return buf */ struct Buf *buf_linedir (struct Buf *buf, const char* filename, int lineno) { char *dst, *src, *t; char *dupe; dupe = flex_alloc (strlen(filename) + 1); strncpy(dupe, filename, strlen(filename)); t = flex_alloc (strlen ("#line \"\"\n") + /* constant parts */ 2 * strlen (filename) + /* filename with possibly all backslashes escaped */ (int) (1 + log10 (abs (lineno))) + /* line number */ 1); /* NUL */ if (!t) flexfatal (_("Allocation of buffer for line directive failed")); for (dst = t + sprintf (t, "#line %d \"", lineno), src = dupe; *src; *dst++ = *src++) if (*src == '\\') /* escape backslashes */ *dst++ = '\\'; *dst++ = '"'; *dst++ = '\n'; *dst = '\0'; buf = buf_strappend (buf, t); flex_free (t); return buf; }
void flexend(int status) { int tblsiz; char *flex_gettime(); if ( skelfile != NULL ) { if ( ferror( skelfile ) ) flexfatal( "error occurred when writing skeleton file" ); else if ( fclose( skelfile ) ) flexfatal( "error occurred when closing skeleton file" ); } if ( temp_action_file ) { if ( ferror( temp_action_file ) ) flexfatal( "error occurred when writing temporary action file" ); else if ( fclose( temp_action_file ) ) flexfatal( "error occurred when closing temporary action file" ); else if ( unlink( action_file_name ) ) flexfatal( "error occurred when deleting temporary action file" ); } if ( status != 0 && outfile_created ) { if ( ferror( stdout ) ) flexfatal( "error occurred when writing output file" ); else if ( fclose( stdout ) ) flexfatal( "error occurred when closing output file" ); else if ( unlink( outfile ) ) flexfatal( "error occurred when deleting output file" ); } if ( backtrack_report && backtrack_file ) { if ( num_backtracking == 0 ) fprintf( backtrack_file, "No backtracking.\n" ); else if ( fullspd || fulltbl ) fprintf( backtrack_file, "%d backtracking (non-accepting) states.\n", num_backtracking ); else fprintf( backtrack_file, "Compressed tables always backtrack.\n" ); if ( ferror( backtrack_file ) ) flexfatal( "error occurred when writing backtracking file" ); else if ( fclose( backtrack_file ) ) flexfatal( "error occurred when closing backtracking file" ); } if ( printstats ) { endtime = flex_gettime(); fprintf( stderr, "%s version %s usage statistics:\n", program_name, flex_version ); fprintf( stderr, " started at %s, finished at %s\n", starttime, endtime ); fprintf( stderr, " scanner options: -" ); if ( backtrack_report ) putc( 'b', stderr ); if ( ddebug ) putc( 'd', stderr ); if ( interactive ) putc( 'I', stderr ); if ( caseins ) putc( 'i', stderr ); if ( ! gen_line_dirs ) putc( 'L', stderr ); if ( performance_report ) putc( 'p', stderr ); if ( spprdflt ) putc( 's', stderr ); if ( use_stdout ) putc( 't', stderr ); if ( trace ) putc( 'T', stderr ); if ( printstats ) putc( 'v', stderr ); /* always true! */ if ( csize == 256 ) putc( '8', stderr ); fprintf( stderr, " -C" ); if ( fulltbl ) putc( 'f', stderr ); if ( fullspd ) putc( 'F', stderr ); if ( useecs ) putc( 'e', stderr ); if ( usemecs ) putc( 'm', stderr ); if ( strcmp( skelname, ENQUOTE(DEFAULT_SKELETON_FILE) ) ) fprintf( stderr, " -S%s", skelname ); putc( '\n', stderr ); fprintf( stderr, " %d/%d NFA states\n", lastnfa, current_mns ); fprintf( stderr, " %d/%d DFA states (%d words)\n", lastdfa, current_max_dfas, totnst ); fprintf( stderr, " %d rules\n", num_rules - 1 /* - 1 for def. rule */ ); if ( num_backtracking == 0 ) fprintf( stderr, " No backtracking\n" ); else if ( fullspd || fulltbl ) fprintf( stderr, " %d backtracking (non-accepting) states\n", num_backtracking ); else fprintf( stderr, " compressed tables always backtrack\n" ); if ( bol_needed ) fprintf( stderr, " Beginning-of-line patterns used\n" ); fprintf( stderr, " %d/%d start conditions\n", lastsc, current_max_scs ); fprintf( stderr, " %d epsilon states, %d double epsilon states\n", numeps, eps2 ); if ( lastccl == 0 ) fprintf( stderr, " no character classes\n" ); else fprintf( stderr, " %d/%d character classes needed %d/%d words of storage, %d reused\n", lastccl, current_maxccls, cclmap[lastccl] + ccllen[lastccl], current_max_ccl_tbl_size, cclreuse ); fprintf( stderr, " %d state/nextstate pairs created\n", numsnpairs ); fprintf( stderr, " %d/%d unique/duplicate transitions\n", numuniq, numdup ); if ( fulltbl ) { tblsiz = lastdfa * numecs; fprintf( stderr, " %d table entries\n", tblsiz ); } else { tblsiz = 2 * (lastdfa + numtemps) + 2 * tblend; fprintf( stderr, " %d/%d base-def entries created\n", lastdfa + numtemps, current_max_dfas ); fprintf( stderr, " %d/%d (peak %d) nxt-chk entries created\n", tblend, current_max_xpairs, peakpairs ); fprintf( stderr, " %d/%d (peak %d) template nxt-chk entries created\n", numtemps * nummecs, current_max_template_xpairs, numtemps * numecs ); fprintf( stderr, " %d empty table entries\n", nummt ); fprintf( stderr, " %d protos created\n", numprots ); fprintf( stderr, " %d templates created, %d uses\n", numtemps, tmpuses ); } if ( useecs ) { tblsiz = tblsiz + csize; fprintf( stderr, " %d/%d equivalence classes created\n", numecs, csize ); } if ( usemecs ) { tblsiz = tblsiz + numecs; fprintf( stderr, " %d/%d meta-equivalence classes created\n", nummecs, csize ); } fprintf( stderr, " %d (%d saved) hash collisions, %d DFAs equal\n", hshcol, hshsave, dfaeql ); fprintf( stderr, " %d sets of reallocations needed\n", num_reallocs ); fprintf( stderr, " %d total table entries needed\n", tblsiz ); } exit( status ); }
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] */ }
int *epsclosure (int *t, int *ns_addr, int accset[], int *nacc_addr, int *hv_addr) { int stkpos, ns, tsp; int numstates = *ns_addr, nacc, hashval, transsym, nfaccnum; int stkend, nstate; static int did_stk_init = false, *stk; #define MARK_STATE(state) \ do{ trans1[state] = trans1[state] - MARKER_DIFFERENCE;} while(0) #define IS_MARKED(state) (trans1[state] < 0) #define UNMARK_STATE(state) \ do{ trans1[state] = trans1[state] + MARKER_DIFFERENCE;} while(0) #define CHECK_ACCEPT(state) \ do{ \ nfaccnum = accptnum[state]; \ if ( nfaccnum != NIL ) \ accset[++nacc] = nfaccnum; \ }while(0) #define DO_REALLOCATION() \ do { \ current_max_dfa_size += MAX_DFA_SIZE_INCREMENT; \ ++num_reallocs; \ t = reallocate_integer_array( t, current_max_dfa_size ); \ stk = reallocate_integer_array( stk, current_max_dfa_size ); \ }while(0) \ #define PUT_ON_STACK(state) \ do { \ if ( ++stkend >= current_max_dfa_size ) \ DO_REALLOCATION(); \ stk[stkend] = state; \ MARK_STATE(state); \ }while(0) #define ADD_STATE(state) \ do { \ if ( ++numstates >= current_max_dfa_size ) \ DO_REALLOCATION(); \ t[numstates] = state; \ hashval += state; \ }while(0) #define STACK_STATE(state) \ do { \ PUT_ON_STACK(state); \ CHECK_ACCEPT(state); \ if ( nfaccnum != NIL || transchar[state] != SYM_EPSILON ) \ ADD_STATE(state); \ }while(0) if (!did_stk_init) { stk = allocate_integer_array (current_max_dfa_size); did_stk_init = true; } nacc = stkend = hashval = 0; for (nstate = 1; nstate <= numstates; ++nstate) { ns = t[nstate]; /* The state could be marked if we've already pushed it onto * the stack. */ if (!IS_MARKED (ns)) { PUT_ON_STACK (ns); CHECK_ACCEPT (ns); hashval += ns; } } for (stkpos = 1; stkpos <= stkend; ++stkpos) { ns = stk[stkpos]; transsym = transchar[ns]; if (transsym == SYM_EPSILON) { tsp = trans1[ns] + MARKER_DIFFERENCE; if (tsp != NO_TRANSITION) { if (!IS_MARKED (tsp)) STACK_STATE (tsp); tsp = trans2[ns]; if (tsp != NO_TRANSITION && !IS_MARKED (tsp)) STACK_STATE (tsp); } } } /* Clear out "visit" markers. */ for (stkpos = 1; stkpos <= stkend; ++stkpos) { if (IS_MARKED (stk[stkpos])) UNMARK_STATE (stk[stkpos]); else flexfatal (_ ("consistency check failed in epsclosure()")); } *ns_addr = numstates; *hv_addr = hashval; *nacc_addr = nacc; return t; }
void sympartition (int ds[], int numstates, int symlist[], int duplist[]) { int tch, i, j, k, ns, dupfwd[CSIZE + 1], lenccl, cclp, ich; /* Partitioning is done by creating equivalence classes for those * characters which have out-transitions from the given state. Thus * we are really creating equivalence classes of equivalence classes. */ for (i = 1; i <= numecs; ++i) { /* initialize equivalence class list */ duplist[i] = i - 1; dupfwd[i] = i + 1; } duplist[1] = NIL; dupfwd[numecs] = NIL; for (i = 1; i <= numstates; ++i) { ns = ds[i]; tch = transchar[ns]; if (tch != SYM_EPSILON) { if (tch < -lastccl || tch >= csize) { flexfatal (_ ("bad transition character detected in sympartition()")); } if (tch >= 0) { /* character transition */ int ec = ecgroup[tch]; mkechar (ec, dupfwd, duplist); symlist[ec] = 1; } else { /* character class */ tch = -tch; lenccl = ccllen[tch]; cclp = cclmap[tch]; mkeccl (ccltbl + cclp, lenccl, dupfwd, duplist, numecs, NUL_ec); if (cclng[tch]) { j = 0; for (k = 0; k < lenccl; ++k) { ich = ccltbl[cclp + k]; if (ich == 0) ich = NUL_ec; for (++j; j < ich; ++j) symlist[j] = 1; } for (++j; j <= numecs; ++j) symlist[j] = 1; } else for (k = 0; k < lenccl; ++k) { ich = ccltbl[cclp + k]; if (ich == 0) ich = NUL_ec; symlist[ich] = 1; } } } } }
void ntod (void) { int *accset, ds, nacc, newds; int sym, hashval, numstates, dsize; int num_full_table_rows=0; /* used only for -f */ int *nset, *dset; int targptr, totaltrans, i, comstate, comfreq, targ; int symlist[CSIZE + 1]; int num_start_states; int todo_head, todo_next; struct yytbl_data *yynxt_tbl = 0; flex_int32_t *yynxt_data = 0, yynxt_curr = 0; /* Note that the following are indexed by *equivalence classes* * and not by characters. Since equivalence classes are indexed * beginning with 1, even if the scanner accepts NUL's, this * means that (since every character is potentially in its own * equivalence class) these arrays must have room for indices * from 1 to CSIZE, so their size must be CSIZE + 1. */ int duplist[CSIZE + 1], state[CSIZE + 1]; int targfreq[CSIZE + 1] = {0}, targstate[CSIZE + 1]; /* accset needs to be large enough to hold all of the rules present * in the input, *plus* their YY_TRAILING_HEAD_MASK variants. */ accset = allocate_integer_array ((num_rules + 1) * 2); nset = allocate_integer_array (current_max_dfa_size); /* The "todo" queue is represented by the head, which is the DFA * state currently being processed, and the "next", which is the * next DFA state number available (not in use). We depend on the * fact that snstods() returns DFA's \in increasing order/, and thus * need only know the bounds of the dfas to be processed. */ todo_head = todo_next = 0; for (i = 0; i <= csize; ++i) { duplist[i] = NIL; symlist[i] = false; } for (i = 0; i <= num_rules; ++i) accset[i] = NIL; if (trace) { dumpnfa (scset[1]); fputs (_("\n\nDFA Dump:\n\n"), stderr); } inittbl (); /* Check to see whether we should build a separate table for * transitions on NUL characters. We don't do this for full-speed * (-F) scanners, since for them we don't have a simple state * number lying around with which to index the table. We also * don't bother doing it for scanners unless (1) NUL is in its own * equivalence class (indicated by a positive value of * ecgroup[NUL]), (2) NUL's equivalence class is the last * equivalence class, and (3) the number of equivalence classes is * the same as the number of characters. This latter case comes * about when useecs is false or when it's true but every character * still manages to land in its own class (unlikely, but it's * cheap to check for). If all these things are true then the * character code needed to represent NUL's equivalence class for * indexing the tables is going to take one more bit than the * number of characters, and therefore we won't be assured of * being able to fit it into a YY_CHAR variable. This rules out * storing the transitions in a compressed table, since the code * for interpreting them uses a YY_CHAR variable (perhaps it * should just use an integer, though; this is worth pondering ... * ###). * * Finally, for full tables, we want the number of entries in the * table to be a power of two so the array references go fast (it * will just take a shift to compute the major index). If * encoding NUL's transitions in the table will spoil this, we * give it its own table (note that this will be the case if we're * not using equivalence classes). */ /* Note that the test for ecgroup[0] == numecs below accomplishes * both (1) and (2) above */ if (!fullspd && ecgroup[0] == numecs) { /* NUL is alone in its equivalence class, which is the * last one. */ int use_NUL_table = (numecs == csize); if (fulltbl && !use_NUL_table) { /* We still may want to use the table if numecs * is a power of 2. */ int power_of_two; for (power_of_two = 1; power_of_two <= csize; power_of_two *= 2) if (numecs == power_of_two) { use_NUL_table = true; break; } } if (use_NUL_table) nultrans = allocate_integer_array (current_max_dfas); /* From now on, nultrans != nil indicates that we're * saving null transitions for later, separate encoding. */ } if (fullspd) { for (i = 0; i <= numecs; ++i) state[i] = 0; place_state (state, 0, 0); dfaacc[0].dfaacc_state = 0; } else if (fulltbl) { if (nultrans) /* We won't be including NUL's transitions in the * table, so build it for entries from 0 .. numecs - 1. */ num_full_table_rows = numecs; else /* Take into account the fact that we'll be including * the NUL entries in the transition table. Build it * from 0 .. numecs. */ num_full_table_rows = numecs + 1; /* Begin generating yy_nxt[][] * This spans the entire LONG function. * This table is tricky because we don't know how big it will be. * So we'll have to realloc() on the way... * we'll wait until we can calculate yynxt_tbl->td_hilen. */ yynxt_tbl = calloc(1, sizeof (struct yytbl_data)); yytbl_data_init (yynxt_tbl, YYTD_ID_NXT); yynxt_tbl->td_hilen = 1; yynxt_tbl->td_lolen = (flex_uint32_t) num_full_table_rows; yynxt_tbl->td_data = yynxt_data = calloc(yynxt_tbl->td_lolen * yynxt_tbl->td_hilen, sizeof (flex_int32_t)); yynxt_curr = 0; buf_prints (&yydmap_buf, "\t{YYTD_ID_NXT, (void**)&yy_nxt, sizeof(%s)},\n", long_align ? "flex_int32_t" : "flex_int16_t"); /* Unless -Ca, declare it "short" because it's a real * long-shot that that won't be large enough. */ if (gentables) out_str_dec ("static const %s yy_nxt[][%d] =\n {\n", long_align ? "flex_int32_t" : "flex_int16_t", num_full_table_rows); else { out_dec ("#undef YY_NXT_LOLEN\n#define YY_NXT_LOLEN (%d)\n", num_full_table_rows); out_str ("static const %s *yy_nxt =0;\n", long_align ? "flex_int32_t" : "flex_int16_t"); } if (gentables) outn (" {"); /* Generate 0 entries for state #0. */ for (i = 0; i < num_full_table_rows; ++i) { mk2data (0); yynxt_data[yynxt_curr++] = 0; } dataflush (); if (gentables) outn (" },\n"); } /* Create the first states. */ num_start_states = lastsc * 2; for (i = 1; i <= num_start_states; ++i) { numstates = 1; /* For each start condition, make one state for the case when * we're at the beginning of the line (the '^' operator) and * one for the case when we're not. */ if (i % 2 == 1) nset[numstates] = scset[(i / 2) + 1]; else nset[numstates] = mkbranch (scbol[i / 2], scset[i / 2]); nset = epsclosure (nset, &numstates, accset, &nacc, &hashval); if (snstods (nset, numstates, accset, nacc, hashval, &ds)) { numas += nacc; totnst += numstates; ++todo_next; if (variable_trailing_context_rules && nacc > 0) check_trailing_context (nset, numstates, accset, nacc); } } if (!fullspd) { if (!snstods (nset, 0, accset, 0, 0, &end_of_buffer_state)) flexfatal (_ ("could not create unique end-of-buffer state")); ++numas; ++num_start_states; ++todo_next; } while (todo_head < todo_next) { targptr = 0; totaltrans = 0; for (i = 1; i <= numecs; ++i) state[i] = 0; ds = ++todo_head; dset = dss[ds]; dsize = dfasiz[ds]; if (trace) fprintf (stderr, _("state # %d:\n"), ds); sympartition (dset, dsize, symlist, duplist); for (sym = 1; sym <= numecs; ++sym) { if (symlist[sym]) { symlist[sym] = 0; if (duplist[sym] == NIL) { /* Symbol has unique out-transitions. */ numstates = symfollowset (dset, dsize, sym, nset); nset = epsclosure (nset, &numstates, accset, &nacc, &hashval); if (snstods (nset, numstates, accset, nacc, hashval, &newds)) { totnst = totnst + numstates; ++todo_next; numas += nacc; if (variable_trailing_context_rules && nacc > 0) check_trailing_context (nset, numstates, accset, nacc); } state[sym] = newds; if (trace) fprintf (stderr, "\t%d\t%d\n", sym, newds); targfreq[++targptr] = 1; targstate[targptr] = newds; ++numuniq; } else { /* sym's equivalence class has the same * transitions as duplist(sym)'s * equivalence class. */ targ = state[duplist[sym]]; state[sym] = targ; if (trace) fprintf (stderr, "\t%d\t%d\n", sym, targ); /* Update frequency count for * destination state. */ i = 0; while (targstate[++i] != targ) ; ++targfreq[i]; ++numdup; } ++totaltrans; duplist[sym] = NIL; } } numsnpairs += totaltrans; if (ds > num_start_states) check_for_backing_up (ds, state); if (nultrans) { nultrans[ds] = state[NUL_ec]; state[NUL_ec] = 0; /* remove transition */ } if (fulltbl) { /* Each time we hit here, it's another td_hilen, so we realloc. */ yynxt_tbl->td_hilen++; yynxt_tbl->td_data = yynxt_data = realloc (yynxt_data, yynxt_tbl->td_hilen * yynxt_tbl->td_lolen * sizeof (flex_int32_t)); if (gentables) outn (" {"); /* Supply array's 0-element. */ if (ds == end_of_buffer_state) { mk2data (-end_of_buffer_state); yynxt_data[yynxt_curr++] = -end_of_buffer_state; } else { mk2data (end_of_buffer_state); yynxt_data[yynxt_curr++] = end_of_buffer_state; } for (i = 1; i < num_full_table_rows; ++i) { /* Jams are marked by negative of state * number. */ mk2data (state[i] ? state[i] : -ds); yynxt_data[yynxt_curr++] = state[i] ? state[i] : -ds; } dataflush (); if (gentables) outn (" },\n"); } else if (fullspd) place_state (state, ds, totaltrans); else if (ds == end_of_buffer_state) /* Special case this state to make sure it does what * it's supposed to, i.e., jam on end-of-buffer. */ stack1 (ds, 0, 0, JAMSTATE); else { /* normal, compressed state */ /* Determine which destination state is the most * common, and how many transitions to it there are. */ comfreq = 0; comstate = 0; for (i = 1; i <= targptr; ++i) if (targfreq[i] > comfreq) { comfreq = targfreq[i]; comstate = targstate[i]; } bldtbl (state, ds, totaltrans, comstate, comfreq); } } if (fulltbl) { dataend (); if (tablesext) { yytbl_data_compress (yynxt_tbl); if (yytbl_data_fwrite (&tableswr, yynxt_tbl) < 0) flexerror (_ ("Could not write yynxt_tbl[][]")); } if (yynxt_tbl) { yytbl_data_destroy (yynxt_tbl); yynxt_tbl = 0; } } else if (!fullspd) { cmptmps (); /* create compressed template entries */ /* Create tables for all the states with only one * out-transition. */ while (onesp > 0) { mk1tbl (onestate[onesp], onesym[onesp], onenext[onesp], onedef[onesp]); --onesp; } mkdeftbl (); } free(accset); free(nset); }
/** 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; }
/* skelout - write out one section of the skeleton file * * Description * Copies skelfile or skel array to stdout until a line beginning with * "%%" or EOF is found. */ void skelout (void) { char buf_storage[MAXLINE]; char *buf = buf_storage; bool do_copy = true; /* "reset" the state by clearing the buffer and pushing a '1' */ if(sko_len > 0) sko_peek(&do_copy); sko_len = 0; sko_push(do_copy=true); /* Loop pulling lines either from the skelfile, if we're using * one, or from the skel[] array. */ while (skelfile ? (fgets (buf, MAXLINE, skelfile) != NULL) : ((buf = (char *) skel[skel_ind++]) != 0)) { if (skelfile) chomp (buf); /* copy from skel array */ if (buf[0] == '%') { /* control line */ /* print the control line as a comment. */ if (ddebug && buf[1] != '#') { if (buf[strlen (buf) - 1] == '\\') out_str ("/* %s */\\\n", buf); else out_str ("/* %s */\n", buf); } /* We've been accused of using cryptic markers in the skel. * So we'll use emacs-style-hyphenated-commands. * We might consider a hash if this if-else-if-else * chain gets too large. */ #define cmd_match(s) (strncmp(buf,(s),strlen(s))==0) if (buf[1] == '#') { /* %# indicates comment line to be ignored */ } else if (buf[1] == '%') { /* %% is a break point for skelout() */ return; } else if (cmd_match (CMD_PUSH)){ sko_push(do_copy); if(ddebug){ out_str("/*(state = (%s) */",do_copy?"true":"false"); } out_str("%s\n", buf[strlen (buf) - 1] =='\\' ? "\\" : ""); } else if (cmd_match (CMD_POP)){ sko_pop(&do_copy); if(ddebug){ out_str("/*(state = (%s) */",do_copy?"true":"false"); } out_str("%s\n", buf[strlen (buf) - 1] =='\\' ? "\\" : ""); } else if (cmd_match (CMD_IF_REENTRANT)){ sko_push(do_copy); do_copy = reentrant && do_copy; } else if (cmd_match (CMD_IF_NOT_REENTRANT)){ sko_push(do_copy); do_copy = !reentrant && do_copy; } else if (cmd_match(CMD_IF_BISON_BRIDGE)){ sko_push(do_copy); do_copy = bison_bridge_lval && do_copy; } else if (cmd_match(CMD_IF_NOT_BISON_BRIDGE)){ sko_push(do_copy); do_copy = !bison_bridge_lval && do_copy; } else if (cmd_match (CMD_ENDIF)){ sko_pop(&do_copy); } else if (cmd_match (CMD_IF_TABLES_SER)) { do_copy = do_copy && tablesext; } else if (cmd_match (CMD_TABLES_YYDMAP)) { if (tablesext && yydmap_buf.elts) outn ((char *) (yydmap_buf.elts)); } else if (cmd_match (CMD_DEFINE_YYTABLES)) { if ( tablesext ) out_str( "#define YYTABLES_NAME \"%s\"\n", tablesname ? tablesname : "yytables" ); } else if (cmd_match (CMD_IF_CPP_ONLY)) { /* only for C++ */ sko_push(do_copy); do_copy = C_plus_plus; } else if (cmd_match (CMD_IF_C_ONLY)) { /* %- only for C */ sko_push(do_copy); do_copy = !C_plus_plus; } else if (cmd_match (CMD_IF_C_OR_CPP)) { /* %* for C and C++ */ sko_push(do_copy); do_copy = true; } else if (cmd_match (CMD_NOT_FOR_HEADER)) { /* %c begin linkage-only (non-header) code. */ OUT_BEGIN_CODE (); } else if (cmd_match (CMD_OK_FOR_HEADER)) { /* %e end linkage-only code. */ OUT_END_CODE (); } else { flexfatal (_("bad line in skeleton file")); } } else if (do_copy) outn (buf); } /* end while */ }
/** 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; }
/** 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; }