5 kx #!/usr/bin/perl -w
5 kx
5 kx use strict;
5 kx use Getopt::Long qw(:config no_ignore_case bundling);
5 kx use File::Basename;
5 kx use utf8;
5 kx
5 kx my $ifname = '';
5 kx my $ofname = '';
5 kx my $stdio = '';
5 kx my $last = '';
5 kx
5 kx my $version = "@VERSION@";
5 kx
5 kx my ( $if, $of );
5 kx
5 kx sub usage
5 kx {
5 kx my $p = basename( $0 );
5 kx
5 kx print <<EOF;
5 kx
5 kx Usage: $p [options] [input_file_name]
5 kx Options:
5 kx --output | -o - output file name;
5 kx --version | -v - print version numver;
5 kx --help | -h | -? - print this message;
5 kx -- - an option terminator;
5 kx - - use std{io|out} instead of files.
5 kx
5 kx Examples:
5 kx
5 kx Input file is 'full.json', output file is 'min.json':
5 kx
5 kx \$ $p -o min.json full.json
5 kx
5 kx Input file is 'STDIN', output file is 'min.json':
5 kx
5 kx \$ $p -o min.json -
5 kx
5 kx Please note that to terminate your input by keyboard you have to use
5 kx <Ctrl>+d combination;
5 kx
5 kx Input file is 'full.json', output file is 'STDOUT':
5 kx
5 kx \$ $p -- full.json
5 kx
5 kx Use stdin, stdout:
5 kx
5 kx \$ $p - < full.json > min.json
5 kx
5 kx Enjoj.
5 kx
5 kx EOF
5 kx exit;
5 kx }
5 kx
5 kx sub version
5 kx {
5 kx print <<EOF;
5 kx $version
5 kx EOF
5 kx exit;
5 kx }
5 kx
5 kx
5 kx my $a = '';
5 kx my $b = '';
5 kx my $x = '';
5 kx my $y = '';
5 kx
5 kx my $lookahead = 0;
5 kx
5 kx
5 kx sub get
5 kx {
5 kx my $c = 0;
5 kx
5 kx $c = $lookahead;
5 kx $lookahead = 0;
5 kx
5 kx if( $c == 0 )
5 kx {
5 kx if( ! eof( $if ) )
5 kx {
5 kx my $ch = getc( $if );
5 kx $c = ord( $ch );
5 kx }
5 kx else
5 kx {
5 kx $c = 0;
5 kx }
5 kx }
5 kx if( $c >= ord(" ") || $c == ord("\n") || $c == 0 )
5 kx {
5 kx return $c;
5 kx }
5 kx if( $c == ord("\r") )
5 kx {
5 kx return ord("\n");
5 kx }
5 kx return ord(" ");
5 kx }
5 kx
5 kx sub peek
5 kx {
5 kx $lookahead = get();
5 kx return $lookahead;
5 kx }
5 kx
5 kx sub next_cn
5 kx {
5 kx my $c = get();
5 kx
5 kx if( $c == ord("/") )
5 kx {
5 kx my $char = chr( peek() );
5 kx if( $char eq "/" )
5 kx {
5 kx for(;;) { $c = get(); if( $c <= ord("\n") ) { last; } }
5 kx }
5 kx elsif( $char eq "*" )
5 kx {
5 kx get();
5 kx while( $c != ord(" ") )
5 kx {
5 kx my $cn = get();
5 kx if( chr( $cn ) eq "*" )
5 kx {
5 kx if( chr( peek() ) eq "/" ) { get(); $c = ord(" "); }
5 kx }
5 kx elsif( $cn == 0 )
5 kx {
5 kx print STDERR "Unterminated comment.\n"; exit 1;
5 kx }
5 kx }
5 kx }
5 kx }
5 kx $y = $x;
5 kx $x = chr( $c );
5 kx
5 kx return $c;
5 kx }
5 kx
5 kx sub action
5 kx {
5 kx my $d = $_[0];
5 kx
5 kx if( $d == 1 )
5 kx {
5 kx print $of $a;
5 kx if(
5 kx ( $y eq "\n" || $y eq " " ) &&
5 kx ( $a eq "+" || $a eq "-" || $a eq "*" || $a eq "/" ) &&
5 kx ( $b eq "+" || $b eq "-" || $b eq "*" || $b eq "/" )
5 kx )
5 kx {
5 kx print $of $y;
5 kx }
5 kx $d = 2;
5 kx }
5 kx
5 kx if( $d == 2 )
5 kx {
5 kx $a = $b;
5 kx if( $a eq "\'" || $a eq "\"" || $a eq "`" )
5 kx {
5 kx for(;;)
5 kx {
5 kx my $c;
5 kx
5 kx print $of $a;
5 kx $c = get(); $a = chr( $c );
5 kx if( $a eq $b ) { last; }
5 kx if( $a eq "\\" )
5 kx {
5 kx print $of $a;
5 kx $c = get(); $a = chr( $c );
5 kx }
5 kx if( $c == 0 )
5 kx {
5 kx print STDERR "Unterminated string literal.\n"; exit 1;
5 kx }
5 kx }
5 kx }
5 kx $d = 3;
5 kx }
5 kx
5 kx if( $d == 3 )
5 kx {
5 kx $b = chr( next_cn() );
5 kx if( $b eq "/" &&
5 kx ( $a eq "(" || $a eq "," || $a eq "=" || $a eq ":" ||
5 kx $a eq "[" || $a eq "!" || $a eq "&" || $a eq "|" ||
5 kx $a eq "?" || $a eq "+" || $a eq "-" || $a eq "~" ||
5 kx $a eq "*" || $a eq "/" || $a eq "{" || $a eq "\n"
5 kx )
5 kx )
5 kx {
5 kx print $of $a;
5 kx if( $a eq "/" || $a eq "*" ) { print $of " "; }
5 kx print $of $b;
5 kx for(;;)
5 kx {
5 kx my $c;
5 kx
5 kx $c = get(); $a = chr( $c );
5 kx if( $a eq "[" )
5 kx {
5 kx for(;;)
5 kx {
5 kx print $of $a;
5 kx $c = get(); $a = chr( $c );
5 kx if( $a eq "]" )
5 kx {
5 kx last;
5 kx }
5 kx if( $a eq "\\" )
5 kx {
5 kx print $of $a;
5 kx $c = get(); $a = chr( $c );
5 kx }
5 kx if( $c == 0 )
5 kx {
5 kx print STDERR "Unterminated regular expression literal.\n"; exit 1;
5 kx }
5 kx }
5 kx }
5 kx elsif( $a eq "/" )
5 kx {
5 kx my $ch = chr( peek() );
5 kx if( $ch eq "/" || $ch eq "*" )
5 kx {
5 kx print STDERR "Unterminated regular expression literal.\n"; exit 1;
5 kx }
5 kx last;
5 kx }
5 kx elsif( $a eq "\\" )
5 kx {
5 kx print $of $a;
5 kx $c = get(); $a = chr( $c );
5 kx }
5 kx elsif( $c == 0 )
5 kx {
5 kx print STDERR "Unterminated regular expression literal.\n"; exit 1;
5 kx }
5 kx print $of $a;
5 kx }
5 kx $b = chr( next_cn() );
5 kx }
5 kx }
5 kx }
5 kx
5 kx
5 kx sub isalnum
5 kx {
5 kx my $ch = $_[0];
5 kx
5 kx if( ($ch ge "a" && $ch le "z") || ($ch ge "0" && $ch le "9") ||
5 kx ($ch ge "A" && $ch le "Z") || $ch eq "_" || $ch eq "\$" ||
5 kx $ch eq "\\" || $ch gt "~"
5 kx ) { return 1; } else { return 0; }
5 kx }
5 kx
5 kx
5 kx sub jsmin
5 kx {
5 kx if( peek() == 0xEF ) { get(); get(); get(); }
5 kx $a = "\n";
5 kx action( 3 );
5 kx while( $a ne "" && $a ne "\0" )
5 kx {
5 kx if( $a eq " " )
5 kx {
5 kx action( isalnum( $b ) ? 1 : 2 );
5 kx }
5 kx elsif( $a eq "\n" )
5 kx {
5 kx if( $b eq "{" || $b eq "[" || $b eq "(" || $b eq "+" ||
5 kx $b eq "-" || $b eq "!" || $b eq "~"
5 kx )
5 kx {
5 kx action( 1 );
5 kx }
5 kx elsif( $b eq " " )
5 kx {
5 kx action( 3 );
5 kx }
5 kx else
5 kx {
5 kx action( isalnum( $b ) ? 1 : 2 );
5 kx }
5 kx }
5 kx else
5 kx {
5 kx if( $b eq " " )
5 kx {
5 kx action( isalnum( $a ) ? 1 : 3 );
5 kx }
5 kx elsif( $b eq "\n" )
5 kx {
5 kx if( $a eq "}" || $a eq "]" || $a eq ")" || $a eq "+" ||
5 kx $a eq "-" || $a eq "\"" || $a eq "\'" || $a eq "`"
5 kx )
5 kx {
5 kx action( 1 );
5 kx }
5 kx else
5 kx {
5 kx action( isalnum( $a ) ? 1 : 3 );
5 kx }
5 kx }
5 kx else
5 kx {
5 kx action( 1 );
5 kx }
5 kx }
5 kx }
5 kx #lats carriage return
5 kx print $of "\n";
5 kx }
5 kx
5 kx
5 kx local $SIG{__WARN__} = sub {
5 kx my $message = shift;
5 kx print STDERR "ERROR: " . $message;
5 kx usage();
5 kx };
5 kx
5 kx if( ! GetOptions( 'o=s' => \$ofname,
5 kx 'output=s' => \$ofname,
5 kx '' => \$stdio,
5 kx 'help|h|?' => sub { usage() },
5 kx 'version|v' => sub { version() }
5 kx )
5 kx )
5 kx {
5 kx usage();
5 kx }
5 kx
5 kx foreach( @ARGV )
5 kx {
5 kx $last = $_;
5 kx
5 kx if( $#ARGV )
5 kx {
5 kx usage();
5 kx }
5 kx
5 kx # NOTE: The '--' is an option terminator!
5 kx # So ./script -- - returns last equal to '-'.
5 kx #
5 kx # The $last argument is a ifname by default;
5 kx #
5 kx }
5 kx
5 kx
5 kx if( $ifname eq '' && $ofname eq '' && ! $stdio )
5 kx {
5 kx usage();
5 kx }
5 kx
5 kx if( $ofname ne '' && $stdio && $last ne '' )
5 kx {
5 kx # like that:
5 kx # ./script -o min.json full.json -
5 kx # ./script -o min.json - full.json
5 kx #
5 kx print "ERROR: Input file defined twice: as 'stdin' and as a orfinary file '$last'\n";
5 kx usage();
5 kx }
5 kx else
5 kx {
5 kx $ifname = $last; $last = '';
5 kx }
5 kx
5 kx if( $ofname eq '' ) { $ofname = '-'; }
5 kx if( $ifname eq '' ) { $ifname = '-'; }
5 kx if( $ifname eq '-' ) { $if = *STDIN; } else { open( $if, "< $ifname" ); }
5 kx if( $ofname eq '-' ) { $of = *STDOUT; } else { open( $of, "> $ofname" ); }
5 kx
5 kx
5 kx jsmin();
5 kx
5 kx
5 kx close $if;
5 kx close $of;
5 kx
5 kx exit 0;