F1e3ab214a976a39cfd713bc93deb10f

Repo is here http://github.com/visionmedia/cssmin looking for any suggestions

// 
// cssmin.c
// 
// (c) 2009 TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
//
 
#include "cssmin.h"
 
#define last l
#define undo (ungetc(n, stream), n)
#define next (n = fgetc(stream), undo)
#define buffer (buf[bufpos++] = c)
#define end (buf[bufpos] = '\0')
#define out (++nchars_out, putchar(c))
#define input (l = c, c = fgetc(stream))
#define stat(S, ...) fprintf(stderr, S "\n", __VA_ARGS__);
#define option(S) (strcmp(argv[1], S) == 0)
 
static int 
minify(FILE *stream) {
  clock_t start = clock();
  char c, l, n, buf[CSSMIN_BUFFER_MAX];
  int bufpos = 0, inblock = 0, nchars = 0, nchars_out = 0;
start:
  switch (++nchars, input) {
    case '\n': goto start;
    case '{' : goto block;
    case '}' : goto blockend;
    case ' ' : goto space;
    case '"' : goto string;
    case EOF : goto finish;
    default  : out;
  }
  goto start;
block:
  out; inblock = 1;
  goto start;
blockend:
  out; inblock = 0;
  goto start;
string:
  out;
  if (input != '"') goto string;
  else out;
  goto start;
space:
  if ((isalpha(last) && isalpha(next)) || // foo bar
      (isalpha(last) && isdigit(next)) || // 1px 0
      (isalpha(last) && next == '"') ||   // 1px "solid"
      (last == '"' && !ispunct(next)) ||  // "solid" red
      (!inblock && next == ':') ||        // foo :last-child
      isdigit(last) ||                    // 0 0
      (next == '*' || last == '*')) out;  // foo * bar
  goto start;
finish:
  stat("bytes: %d", nchars);
  stat("bytes saved: %d", nchars - nchars_out);
  stat("duration: %0.5f milliseconds", (float) (clock() - start) / CLOCKS_PER_SEC);
  return 0;
}
 
static int
usage() {
  printf("cssmin: %s\n"
         "usage: cssmin < in.css > out.min.css\n", CSSMIN_VERSION);
  exit(0);
}
 
int 
main(int argc, char **argv) {
  if (argc > 1)
    if (option("--help")) usage();
    else if (option("--version")) puts(CSSMIN_VERSION), exit(0);
  return minify(stdin);
}

Refactorings

No refactoring yet !

F9a9ba6663645458aa8630157ed5e71e

Ants

December 1, 2009, December 01, 2009 23:07, permalink

No rating. Login to rate!

Nice! A state machine implemented within a single function with the use of goto's. :-)

The buf stack variable looks unused.

The next macro looks awfully inefficient doing a fgetc() and then followed by an ungetc(), especially in the handler for 'space'. Why not just peek at the next character once and store that in a variable? Or even better read chunks of characters into the unused buf variable and do the scanning of the current character there so that you don't have the I/O overhead?

F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

December 2, 2009, December 02, 2009 00:47, permalink

No rating. Login to rate!

my bad, think your right. The macros were from another project that actually needed to buffer strings. I previously thought that fgetc() did some internal stream buffering, but I could not find the source or much info but yeah wow in my other project after just using fread() its a huge huge performance gain

F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

December 2, 2009, December 02, 2009 00:49, permalink

No rating. Login to rate!

I like keeping the state machines really simple, all the local vars kinda suck though, limited to macros

F9a9ba6663645458aa8630157ed5e71e

Ants

December 3, 2009, December 03, 2009 08:55, permalink

No rating. Login to rate!

I must be missing something reading the code, but how are the comments in the CSS stripped out? As I read the code now, it looks like comments are left in place, albeit with extra spaces trimmed out.

F9a9ba6663645458aa8630157ed5e71e

Ants

December 7, 2009, December 07, 2009 20:59, permalink

No rating. Login to rate!

I was doing a first pass of refactoring and noticed that the string handler is not bumping up nchars. This probably is skewing your compression numbers.

Your refactoring





Format Copy from initial code

or Cancel