602 lines
16 KiB
C
602 lines
16 KiB
C
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
* 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <ctype.h>
|
|
|
|
|
|
/*======================================================================
|
|
* 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
|
|
\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|