JavaScript, Json minimizator

jsmin – is a JavaScript, Json minimizator which removes comments and unnecessary whitespace from JS, JSON files

6 Commits   0 Branches   1 Tag
Index: Makefile.am
===================================================================
--- Makefile.am	(nonexistent)
+++ Makefile.am	(revision 5)
@@ -0,0 +1,6 @@
+
+bin_PROGRAMS  = jsmin
+
+jsmin_SOURCES = main.c
+
+jsmin_CFLAGS  = -Wall -funsigned-char -I$(top_srcdir)
Index: main.c
===================================================================
--- main.c	(nonexistent)
+++ main.c	(revision 5)
@@ -0,0 +1,533 @@
+
+#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
+/**************************************************************
+  For building outside from source package as a single C file:
+
+    $ gcc -o jsmin main.c
+ */
+
+#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;
+
+/*
+   get - return the next character from stdin. Watch out for lookahead. If
+         the character is a control character, translate it to a space or
+         linefeed.
+ */
+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 ' ';
+}
+
+
+/*
+   peek - get the next character without getting it.
+ */
+static int
+peek()
+{
+  lookahead = get();
+  return lookahead;
+}
+
+
+/*
+   next - get the next character, excluding comments. peek() is used to see
+          if a '/' is followed by a '/' or '*'.
+ */
+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;
+}
+
+
+/*
+   action - do something! What you do is determined by the argument:
+            1   Output A. Copy B to A. Get the next B.
+            2   Copy B to A. Get the next B. (Delete A).
+            3   Get the next B. (Delete B).
+   action treats a string as a single character. Wow!
+   action recognizes a regular expression if it is preceded by ( or , or =.
+ */
+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();
+    }
+  }
+}
+
+
+/*
+   jsmin - Copy the input to the output, deleting the characters which are
+           insignificant to JavaScript. Comments will be removed. Tabs will be
+           replaced with spaces. Carriage returns will be replaced with linefeeds.
+           Most spaces and linefeeds will be removed.
+*/
+
+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;
+        }
+    }
+  }
+  /* lats carriage return */
+  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 ) )
+    {
+      /*
+        use temporary file to presave file content
+        in case when input and output the same file.
+       */
+      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 );
+}
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,25 ##
+
+autom4te.cache/
+
+Makefile
+Makefile.in
+config.h
+config.h.in
+config.log
+config.status
+compile
+config.guess
+config.sub
+configure
+install-sh
+missing
+stamp-h1
+aclocal.m4
+depcomp
+
+perl/Makefile.in
+
+src/.deps/
+src/Makefile.in
+
+*~