/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* * flatex.c - * Flatten a latex file into a single file, by explicitly including * the files inclued by \include and \input commands. Also, if bibtex is * beeing used, then includes the .bbl file into the resulting file. Thus, * creating a stand alone latex file that can be emailed to someone else. * * Compile : gcc -o flatex flatex.c * Tested on : Linux + gcc * By : Sariel Har-Peled * Email : sariel@math.tau.ac.il * WEB Page : http://www.math.tau.ac.il/~sariel/flatex.html * Status : You can do whatever you like with this program. please * email me bugs & suggestions. * * To do : Add support to the includeonly command. *----------------------------------------------------------------------- * FLATEX 1.21, 1994, 1996, by Sariel Har-Peled. * * flatex - create a single latex file with no include/inputs * * flatex [-v] [-x FileName] [files] * -v Verbose, display file structure. * -x Unflatex: extract files from archive * -q Quiet mode. Cleaner output but -x can not be used. * -b Do not insert bibiliography file(.bbl) * * Flatex page: http://www.math.tau.ac.il/~sariel/flatex.html *----------------------------------------------------------------------- * History: * 26/8/96, 1.21 * Fixed bug with includegraphics command. \*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ #include #include #include #include #include /*====================================================================== * Static constants. \*======================================================================*/ #define LINE_SIZE 1000 #define FALSE 0 #define TRUE 1 #define USE_ARGUMENT( X ) ((void)X) /*====================================================================== * Types \*======================================================================*/ typedef struct { char verbose; char fBibInsert, fQuiet; int cSpecialInputLevel; char szFullName[ LINE_SIZE ]; } structFlags; /*====================================================================== * Static prototypes. \*======================================================================*/ static void flatIt( FILE * flOut, char * szInName, int level, structFlags * pFlags ); static void replaceExt( char * str, char * ext ); /*====================================================================== * Start of Code \*======================================================================*/ static void spacesByLevel( int level ) { while ( level > 0 ) { printf( " " ); level--; } } static void printHelp( void ) { printf( "flatex - create a single latex file with no include/inputs\n" ); printf( "\n\tflatex [-v] [-x FileName] [files]\n" ); printf( "\t\t-v\tVerbose, display file structure.\n" ); printf( "\t\t-x\tUnflatex: extract files from archive\n" ); printf( "\t\t-q\tQuiet mode. Cleaner output but -x can not be used.\n" ); printf( "\t\t-b\tDo not insert bibiliography file(.bbl)\n" ); printf( "\nFlatex page: http://www.math.tau.ac.il/~sariel/flatex.html\n" ); printf( "\n" ); } static void * myMalloc( unsigned int size ) { void * ptr; ptr = malloc( size ); if ( ptr == NULL ) { fprintf( stderr, "Not enough memory" ); exit( -1 ); } return ptr; } static void handleIncludeCommand( char * line, char * lpszInclude, FILE * flOut, int level, structFlags * pFlags ) { char * lpszBrace, * lpszName, * lpszEndBrace; char ch, fInput = 0; lpszBrace = NULL; if ( strncmp( lpszInclude, "\\input", 6 ) == 0 ) { lpszBrace = lpszInclude + 6; fInput = 1; } else if ( strncmp( lpszInclude, "\\include", 8 ) == 0 ) { lpszBrace = lpszInclude + 8; } ch = *lpszInclude; *lpszInclude = 0; fputs( line, flOut ); *lpszInclude = ch; lpszEndBrace = strchr( lpszBrace, '}' ); if ( *lpszBrace != '{' || lpszEndBrace == NULL ) { fprintf( stderr, "ERROR: Expected brace not found.\n\n\tline:%s\n", line ); exit( -1 ); } *lpszEndBrace = 0; lpszName = (char *)myMalloc( LINE_SIZE ); strcpy( lpszName, lpszBrace + 1 ); if ( ! fInput ) replaceExt( lpszName, ".tex" ); flatIt( flOut, lpszName, level + 1, pFlags ); lpszEndBrace++; while ( *lpszEndBrace ) { *line++ = *lpszEndBrace++; } *line = 0; free( lpszName ); } static char isBefore( char * lpszA, char * lpszB ) { if ( lpszB == NULL ) return TRUE; if ( lpszA == NULL ) return FALSE; if ( (int)( lpszA -lpszB ) < 0 ) { return TRUE; } return FALSE; } static FILE * fopenTex( char * file, char * mode ) { FILE * fl; fl = fopen( file, mode ); if ( fl != NULL ) return fl; replaceExt( file, ".tex" ); fl = fopen( file, mode ); return fl; } static char isTexFileExists( char * file ) { FILE * fl; fl = fopenTex( file, "rt" ); if ( fl != NULL ) { fclose( fl ); return 1; } return 0; } static void addTexExt( char * file ) { FILE * fl; fl = fopenTex( file, "rt"); if ( fl != NULL ) fclose( fl ); } static char is_str_prefix( char * str, char * prefix ) { int len; if ( str == NULL || prefix == NULL ) return 0; len = strlen( prefix ); return (strncmp( str, prefix, len ) == 0); } static void flatIt( FILE * flOut, char * pSzInName, int level, structFlags * pFlags ) { FILE * flIn; char * str, * lpszInput, * lpszInclude, * line, * lpszRem, *inc; char * lpszLine, * lpszRemark, * lpszBib, * lpszBibStyle; char * lpszNewCommand, * lpszName; char cont; char repFlag; char szInName[ 100 ]; char fInclude; strcpy( szInName, pSzInName ); addTexExt( szInName ); if ( ! pFlags->fQuiet ) fprintf( flOut, "%%%cflatex input: [%s]\n", pFlags->cSpecialInputLevel > 0? '*' : ' ', szInName ); if ( pFlags->verbose ) { printf( "\t" ); spacesByLevel( level ); printf( "%s\n", szInName ); } line = (char *)myMalloc( LINE_SIZE ); lpszLine = (char *)myMalloc( LINE_SIZE ); lpszRemark = (char *)myMalloc( LINE_SIZE ); flIn = fopenTex( szInName, "rt" ); if ( flIn == NULL ) { fprintf( stderr, "Unable to open file: %s\n", szInName ); exit( -1 ); } *lpszRemark = 0; while ( ! feof( flIn ) ) { str = fgets( line, LINE_SIZE, flIn ); if ( str == NULL ) break; fInclude = FALSE; strcpy( lpszLine, line ); lpszRem = strchr( line, '%' ); if ( lpszRem != NULL ) { strcpy( lpszRemark, lpszRem ); *lpszRem = 0; } do { cont = 0; lpszInput = strstr( line, "\\input" ); lpszBib = strstr( line, "\\bibliography" ); lpszBibStyle = strstr( line, "\\bibliographystyle" ); if ( pFlags->fBibInsert && ( lpszBib != NULL || lpszBibStyle != NULL ) ) { lpszName = (char *)myMalloc( LINE_SIZE ); strcpy( lpszName, lpszLine ); strcpy( lpszLine, pFlags->fQuiet? "%" : "%FLATEX-REM:" ); strcat( lpszLine, lpszName ); if ( lpszBibStyle != NULL ) { strcpy( lpszName, pFlags->szFullName ); replaceExt( lpszName, ".bbl" ); pFlags->cSpecialInputLevel++; flatIt( flOut, lpszName, level + 1, pFlags ); pFlags->cSpecialInputLevel--; if ( pFlags->verbose ) { printf( "\t" ); spacesByLevel( level + 1 ); printf( "(Bibiliography)\n" ); } } break; } inc = line; do { repFlag = 0; lpszInclude = strstr( inc, "\\include" ); if ( is_str_prefix( lpszInclude, "\\includeversion" ) || is_str_prefix( lpszInclude, "\\includegraphics" ) ) { repFlag = 1; inc = lpszInclude + 1; continue; } if ( is_str_prefix( lpszInclude, "\\includeonly" ) ) { fprintf( stderr, "WARNING: \"\\includeonly\" command " "ignored\n" ); inc = lpszInclude + 1; repFlag = 1; continue; } if ( lpszInclude != NULL && isalpha( lpszInclude[ 8 ] ) ) { fprintf( stderr, "\nWarning: include-like(?) command ignored" " at line:\n\t%s", lpszLine ); inc = lpszInclude + 1; repFlag = 1; continue; } } while ( repFlag ); if ( isBefore( lpszInput, lpszInclude ) ) lpszInclude = lpszInput; if ( lpszInclude != NULL ) { lpszNewCommand = strstr( line, "\\newcommand" ); if ( lpszNewCommand == NULL ) { handleIncludeCommand( line, lpszInclude, flOut, level, pFlags ); cont = 1; fInclude = TRUE; } } } while ( cont ); if ( fInclude ) { strcat( line, lpszRemark ); fputs( line, flOut ); } else fputs( lpszLine, flOut ); } fclose( flIn ); fputs( "\n", flOut ); if ( ! pFlags->fQuiet ) fprintf( flOut, "%% flatex input end: [%s]\n", szInName ); free( line ); free( lpszLine ); free( lpszRemark ); } static void replaceExt( char * str, char * ext ) { int len, ind; len = strlen( str ); ind = len - 1; while ( ind >= 0 && str[ ind ] != '.' && str[ ind ] != '\\' && str[ ind ] != '/' ) ind--; if ( ind >= 0 && str[ ind ] == '.' ) { str[ ind ] = 0; } strcat( str, ext ); } static char strCmpPrefixAndCopy( char * line, char * str, char * outName ) { char * pos, * pPreLine; pPreLine = line; pos = strstr( line, str ); if ( pos == NULL ) return 0; line = pos + strlen( str ); strcpy( outName, line ); pos = strchr( outName, ']' ); if ( pos == NULL ) { fprintf( stderr, "Error encountered in line: [%s]", pPreLine ); exit( -1 ); } *pos = 0; return 1; } static void writeFile( FILE * flIn, char * pOutName, int level ) { FILE * flOut; char * lpszLine; char line[ LINE_SIZE ], outName[ LINE_SIZE ]; char flag; outName[ 0 ] = 0; if ( pOutName == NULL ) { flOut = NULL; printf( "Scanning for flatex archive start...\n" ); } else { flOut = fopen( pOutName, "wt" ); if ( flOut == NULL ) { fprintf( stderr, "Unable to open file: %s", pOutName ); exit( -1 ); } spacesByLevel( level ); printf( "[%s]\n", pOutName ); } do { lpszLine = fgets( line, LINE_SIZE, flIn ); if ( lpszLine == NULL ) break; flag = strCmpPrefixAndCopy( line, "% flatex input end: [", outName ); if ( flag ) { if ( flOut == NULL ) { fprintf( stderr, "Something is wrong!!!!\n" ); exit( -1 ); } //spacesByLevel( level ); // printf( "/\n" ); //printf( "Writing [%s] done\n", outName ); break; } flag = strCmpPrefixAndCopy( line, "% flatex input: [", outName ); if ( flag ) { writeFile( flIn, outName, level + 1 ); if ( flOut != NULL ) fprintf( flOut, "\\input{%s}\n", outName ); } else { flag = strCmpPrefixAndCopy( line, "%*flatex input: [", outName ); if ( flag ) { writeFile( flIn, outName, level + 1 ); } else { if ( flOut != NULL ) { if ( strncmp( line, "%FLATEX-REM:", 12 ) == 0 ) fputs( line + 12, flOut ); else fputs( line, flOut ); } } } } while ( ! feof( flIn ) ); if ( flOut != NULL ) fclose( flOut ); } static void flatOutFile( char * fileName, structFlags * pFlags ) { FILE * flIn; USE_ARGUMENT( pFlags ); flIn = fopen( fileName, "rt" ); if ( flIn == NULL ) { fprintf( stderr, "Unable to open file: %s", fileName ); exit( -1 ); } writeFile( flIn, NULL, 0 ); fclose( flIn ); } static void flatFile( char * fileName, structFlags * pFlags ) { char * szInName, * szOutName; int inLen; FILE * flOut; szInName = (char *)myMalloc( LINE_SIZE ); szOutName = (char *)myMalloc( LINE_SIZE ); strcpy( szInName, fileName ); if ( ! isTexFileExists( szInName ) ) { fprintf( stderr, "--Unable to open file: [%s]\n", fileName ); exit( -1 ); } inLen = strlen( szInName ); if ( inLen < 4 || ( szInName[ inLen ] != '.' && strcmp( szInName + inLen - 4, ".tex" ) != 0 ) ) { strcat( szInName, ".tex" ); } printf( "input file: [%s]\n", szInName ); strcpy( pFlags->szFullName, szInName ); strcpy( szOutName, szInName ); replaceExt( szOutName, ".flt" ); flOut = fopen( szOutName, "wt" ); if ( flOut == NULL ) { fprintf( stderr, "Unable to open file: %s", szOutName ); exit( -1 ); } flatIt( flOut, szInName, 0, pFlags ); fclose( flOut ); printf( "\n\tFile: \"%s\" generated\n", szOutName ); } static char isFlag( char * str, char ch ) { if ( str[ 0 ] == '-' && ( str[ 1 ] == ch || str[ 1 ] == toupper( ch ) ) && ( str[ 2 ] == 0 ) ) return TRUE; return FALSE; } int main( int argc, char * argv[] ) { int ind; structFlags sFlags; printf( "FLATEX 1.21, 1994, 1996, by Sariel Har-Peled.\n\n" ); if ( argc == 1 ) printHelp(); sFlags.verbose = FALSE; sFlags.fBibInsert = TRUE; sFlags.cSpecialInputLevel = 0; *sFlags.szFullName = 0; sFlags.fQuiet = FALSE; for ( ind = 1; ind < argc; ind++ ) { if ( isFlag( argv[ ind ], 'v' ) ) { sFlags.verbose = TRUE; continue; } if ( isFlag( argv[ ind ], 'b' ) ) { sFlags.fBibInsert = FALSE; continue; } if ( isFlag( argv[ ind ], 'q' ) ) { sFlags.fQuiet = TRUE; continue; } if ( isFlag( argv[ ind ], 'x' ) ) { flatOutFile( argv[ ind + 1 ], &sFlags ); ind++; continue; } flatFile( argv[ ind ], &sFlags ); } return 0; } /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* * * flatex.c - End of File \*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/