| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| |
| #ifdef HAVE_FCNTL_H |
| #include <fcntl.h> |
| #endif |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| |
| #ifdef HAVE_SYS_STAT_H |
| #include <sys/stat.h> |
| #endif |
| |
| #ifdef HAVE_ERRNO_H |
| #include <errno.h> |
| #endif |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #endif |
| |
| #ifdef HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #ifdef HAVE_STDIO_H |
| #include <stdio.h> |
| #endif |
| #ifdef HAVE_GETOPT_H |
| #include <getopt.h> |
| #endif |
| |
| #else |
| |
| |
| |
| |
| |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include <sys/stat.h> |
| |
| #include <errno.h> |
| #include <string.h> |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <getopt.h> |
| |
| #endif |
| |
| static char *ifname = NULL; |
| static char *ofname = NULL; |
| |
| FILE *ifile; |
| FILE *ofile; |
| FILE *tmp; |
| |
| static char *progname = NULL; |
| |
| static int opt_usage; |
| static int opt_version; |
| |
| #define DIR_SEPARATOR '/' |
| |
| static void usage() |
| { |
| printf( "\n" ); |
| printf( "Usage: %s [options] [input_file_name]\n", progname ); |
| printf( "Options:\n" ); |
| printf( " --output | -o - output file name;\n" ); |
| printf( " --version | -v - print version numver;\n" ); |
| printf( " --help | -h | -? - print this message;\n" ); |
| printf( " -- - an option terminator;\n" ); |
| printf( " - - use std{io|out} instead of files.\n\n" ); |
| printf( "Examples:\n\n" ); |
| printf( " Input file is 'full.json', output file is 'min.json':\n\n" ); |
| printf( " $ %s -o min.json full.json\n\n", progname ); |
| printf( " Input file is 'STDIN', output file is 'min.json':\n\n" ); |
| printf( " $ %s -o min.json -\n\n", progname ); |
| printf( " Please note that to terminate your input by keyboard you have to use\n" ); |
| printf( " <Ctrl>+d combination;\n\n" ); |
| printf( " Input file is 'full.json', output file is 'STDOUT':\n\n" ); |
| printf( " $ %s -- full.json\n\n", progname ); |
| printf( " Use stdin, stdout:\n\n" ); |
| printf( " $ %s - < full.json > min.json\n\n", progname ); |
| printf( "Enjoj.\n\n" ); |
| |
| exit( 1 ); |
| } |
| |
| static void version() |
| { |
| #ifdef HAVE_CONFIG_H |
| printf( "%s\n", (char *)VERSION ); |
| #else |
| printf( "0.0.1\n" ); |
| #endif |
| |
| exit( 1 ); |
| } |
| |
| static void |
| error( char *s ) |
| { |
| fprintf( stderr, "ERROR: %s: ", progname ); |
| fprintf( stderr, "%s\n", s ); |
| exit( 1 ); |
| } |
| |
| static int |
| is_alpha_or_num( int c ) |
| { |
| return( (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || |
| (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' || c > 126 ); |
| } |
| |
| static int a; |
| static int b; |
| static int lookahead = EOF; |
| static int x = EOF; |
| static int y = EOF; |
| |
| |
| |
| |
| |
| |
| static int |
| get() |
| { |
| int c = lookahead; |
| lookahead = EOF; |
| if( c == EOF ) |
| { |
| c = getc( ifile ); |
| } |
| if( c >= ' ' || c == '\n' || c == EOF ) |
| { |
| return c; |
| } |
| if( c == '\r' ) |
| { |
| return '\n'; |
| } |
| return ' '; |
| } |
| |
| |
| |
| |
| |
| static int |
| peek() |
| { |
| lookahead = get(); |
| return lookahead; |
| } |
| |
| |
| |
| |
| |
| |
| static int |
| next() |
| { |
| int c = get(); |
| if ( c == '/' ) |
| { |
| switch( peek() ) |
| { |
| case '/': |
| for( ;; ) |
| { |
| c = get(); |
| if( c <= '\n' ) |
| { |
| break; |
| } |
| } |
| break; |
| case '*': |
| get(); |
| while( c != ' ' ) |
| { |
| switch( get() ) |
| { |
| case '*': |
| if( peek() == '/' ) |
| { |
| get(); |
| c = ' '; |
| } |
| break; |
| case EOF: |
| error( "Unterminated comment" ); |
| } |
| } |
| break; |
| } |
| } |
| y = x; |
| x = c; |
| return c; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void |
| action( int d ) |
| { |
| switch( d ) |
| { |
| case 1: |
| putc( a, ofile ); |
| if( (y == '\n' || y == ' ') && |
| (a == '+' || a == '-' || a == '*' || a == '/') && |
| (b == '+' || b == '-' || b == '*' || b == '/') ) |
| { |
| putc( y, ofile ); |
| } |
| case 2: |
| a = b; |
| if( a == '\'' || a == '"' || a == '`' ) |
| { |
| for( ;; ) |
| { |
| putc( a, ofile ); |
| a = get(); |
| if( a == b ) |
| { |
| break; |
| } |
| if( a == '\\' ) |
| { |
| putc( a, ofile ); |
| a = get(); |
| } |
| if( a == EOF ) |
| { |
| error( "Unterminated string literal" ); |
| } |
| } |
| } |
| case 3: |
| b = next(); |
| if( b == '/' && |
| ( a == '(' || a == ',' || a == '=' || a == ':' || |
| a == '[' || a == '!' || a == '&' || a == '|' || |
| a == '?' || a == '+' || a == '-' || a == '~' || |
| a == '*' || a == '/' || a == '{' || a == '\n' ) ) |
| { |
| putc( a, ofile ); |
| if( a == '/' || a == '*' ) |
| { |
| putc( ' ', ofile ); |
| } |
| putc( b, ofile ); |
| for( ;; ) |
| { |
| a = get(); |
| if( a == '[' ) |
| { |
| for( ;; ) |
| { |
| putc( a, ofile ); |
| a = get(); |
| if( a == ']' ) |
| { |
| break; |
| } |
| if( a == '\\' ) |
| { |
| putc( a, ofile ); |
| a = get(); |
| } |
| if( a == EOF ) |
| { |
| error( "Unterminated set in Regular Expression literal" ); |
| } |
| } |
| } |
| else if( a == '/' ) |
| { |
| switch( peek() ) |
| { |
| case '/': |
| case '*': |
| error( "Unterminated set in Regular Expression literal" ); |
| } |
| break; |
| } |
| else if( a =='\\' ) |
| { |
| putc( a, ofile ); |
| a = get(); |
| } |
| if( a == EOF ) |
| { |
| error( "Unterminated Regular Expression literal" ); |
| } |
| putc( a, ofile ); |
| } |
| b = next(); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void |
| jsmin() |
| { |
| if( peek() == 0xEF ) { get(); get(); get(); } |
| a = '\n'; |
| action( 3 ); |
| |
| while( a != EOF ) |
| { |
| switch( a ) |
| { |
| case ' ': |
| action(is_alpha_or_num(b) ? 1 : 2); |
| break; |
| case '\n': |
| switch( b ) |
| { |
| case '{': case '[': case '(': |
| case '+': case '-': case '!': |
| case '~': |
| action( 1 ); |
| break; |
| case ' ': |
| action( 3 ); |
| break; |
| default: |
| action( is_alpha_or_num(b) ? 1 : 2 ); |
| } |
| break; |
| default: |
| switch( b ) |
| { |
| case ' ': |
| action( is_alpha_or_num(a) ? 1 : 3 ); |
| break; |
| case '\n': |
| switch( a ) |
| { |
| case '}': case ']': case ')': |
| case '+': case '-': case '"': |
| case '\'': case '`': |
| action( 1 ); |
| break; |
| default: |
| action( is_alpha_or_num(a) ? 1 : 3 ); |
| } |
| break; |
| default: |
| action( 1 ); |
| break; |
| } |
| } |
| } |
| |
| putc( '\n', ofile ); |
| } |
| |
| int is_file_exist( const char *filename ) |
| { |
| struct stat st; |
| int result = stat( filename, &st ); |
| return result == 0; |
| } |
| |
| static void |
| getargs( argc, argv ) |
| int argc; |
| char *argv[]; |
| { |
| int option = 0; |
| int option_index = 0; |
| static struct option long_options[] = |
| { |
| { "output", required_argument, 0, 'o' }, |
| { "help", no_argument, 0, 'h' }, |
| { "version", no_argument, 0, 'v' }, |
| { 0, 0, 0, 0 }, |
| }; |
| |
| opterr = 0; |
| |
| while( (option = getopt_long( argc, argv, "o:hv", long_options, &option_index )) != -1 ) |
| { |
| switch( option ) |
| { |
| case 'o': |
| ofname = optarg; |
| break; |
| case 'h': |
| opt_usage = 1; |
| break; |
| case 'v': |
| opt_version = 1; |
| break; |
| case '?': |
| { |
| if( optopt == 'o' ) |
| fprintf( stderr,"\nERROR: %s: option '-%c' requires an argument\n\n", progname, optopt ); |
| } |
| default: |
| usage(); |
| break; |
| } |
| } |
| |
| if( optind < argc ) |
| { |
| ifname = argv[optind++]; |
| if( optind < argc ) usage(); |
| } |
| |
| if( opt_usage ) usage(); |
| if( opt_version ) version(); |
| if( opt_usage || ( ! ifname && ! ofname ) ) usage(); |
| |
| if( ! ofname ) ofname = "-" ; |
| if( ! ifname ) ifname = "-" ; |
| } |
| |
| int main( int argc, char *argv[] ) |
| { |
| int use_stdin = 0, use_stdout = 0, use_tmpfile = 0; |
| |
| progname = rindex( argv[0], DIR_SEPARATOR ) + 1; |
| getargs( argc, argv ); |
| |
| |
| if( ! strncmp( ifname, "-", 1 ) ) |
| { |
| ifile = stdin; |
| use_stdin = 1; |
| } |
| else |
| { |
| ifile = fopen( ifname, "r" ); |
| if( ifile == NULL ) |
| { |
| fprintf( stderr, "ERROR: Can't open '%s' file\n", ifname ); |
| exit( 1 ); |
| } |
| } |
| |
| if( ! strncmp( ofname, "-", 1 ) ) |
| { |
| ofile = stdout; |
| use_stdout = 1; |
| } |
| else |
| { |
| if( is_file_exist( ofname ) ) |
| { |
| |
| |
| |
| |
| ofile = tmpfile(); |
| if( ofile == NULL ) |
| { |
| fprintf( stderr, "ERROR: Can't open TEMPORARY file\n" ); |
| exit( 1 ); |
| } |
| use_tmpfile = 1; |
| } |
| else |
| { |
| ofile = fopen( ofname, "w+" ); |
| if( ofile == NULL ) |
| { |
| fprintf( stderr, "ERROR: Can't open '%s' file\n", ofname ); |
| exit( 1 ); |
| } |
| } |
| } |
| |
| |
| jsmin(); |
| |
| |
| if( use_tmpfile ) |
| { |
| tmp = fopen( ofname, "w+" ); |
| if( tmp == NULL ) |
| { |
| fprintf( stderr, "ERROR: Can't open '%s' file\n", ofname ); |
| exit( 1 ); |
| } |
| if( !fseek( ofile, 0, SEEK_SET ) ) |
| { |
| int c; |
| while( (c = getc( ofile )) != EOF ) |
| { |
| putc( c, tmp ); |
| } |
| fclose( tmp ); |
| } |
| else |
| { |
| fprintf( stderr, "ERROR: Can't seek to beginning of the '%s' file\n", ofname ); |
| fclose( tmp ); |
| exit( 1 ); |
| } |
| } |
| |
| if( ! use_stdin ) { fclose( ifile ); ifile = NULL; } |
| if( ! use_stdout ) { fclose( ofile ); ofile = NULL; } |
| exit( 0 ); |
| } |
| |