123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- /* jsmin.c
- 2012-04-15
- Copyright (c) 2002 Douglas Crockford (www.crockford.com)
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- The Software shall be used for Good, not Evil.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- static int theA;
- static int theB;
- static int theLookahead = EOF;
- /* isAlphanum -- return true if the character is a letter, digit, underscore,
- dollar sign, or non-ASCII character.
- */
- static int
- isAlphanum(int c)
- {
- return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
- (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
- c > 126);
- }
- /* 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 = theLookahead;
- theLookahead = EOF;
- if (c == EOF) {
- c = getc(stdin);
- }
- 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()
- {
- theLookahead = get();
- return theLookahead;
- }
- /* 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') {
- return c;
- }
- }
- case '*':
- get();
- for (;;) {
- switch (get()) {
- case '*':
- if (peek() == '/') {
- get();
- return ' ';
- }
- break;
- case EOF:
- fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
- exit(1);
- }
- }
- default:
- return 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(theA, stdout);
- case 2:
- theA = theB;
- if (theA == '\'' || theA == '"' || theA == '`') {
- for (;;) {
- putc(theA, stdout);
- theA = get();
- if (theA == theB) {
- break;
- }
- if (theA == '\\') {
- putc(theA, stdout);
- theA = get();
- }
- if (theA == EOF) {
- fprintf(stderr, "Error: JSMIN unterminated string literal.");
- exit(1);
- }
- }
- }
- case 3:
- theB = next();
- if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
- theA == ':' || theA == '[' || theA == '!' ||
- theA == '&' || theA == '|' || theA == '?' ||
- theA == '{' || theA == '}' || theA == ';' ||
- theA == '\n')) {
- putc(theA, stdout);
- putc(theB, stdout);
- for (;;) {
- theA = get();
- if (theA == '[') {
- for (;;) {
- putc(theA, stdout);
- theA = get();
- if (theA == ']') {
- break;
- }
- if (theA == '\\') {
- putc(theA, stdout);
- theA = get();
- }
- if (theA == EOF) {
- fprintf(stderr,
- "Error: JSMIN unterminated set in Regular Expression literal.\n");
- exit(1);
- }
- }
- } else if (theA == '/') {
- break;
- } else if (theA =='\\') {
- putc(theA, stdout);
- theA = get();
- }
- if (theA == EOF) {
- fprintf(stderr,
- "Error: JSMIN unterminated Regular Expression literal.\n");
- exit(1);
- }
- putc(theA, stdout);
- }
- theB = 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();
- }
- theA = '\n';
- action(3);
- while (theA != EOF) {
- switch (theA) {
- case ' ':
- if (isAlphanum(theB)) {
- action(1);
- } else {
- action(2);
- }
- break;
- case '\n':
- switch (theB) {
- case '{':
- case '[':
- case '(':
- case '+':
- case '-':
- case '!':
- case '~':
- action(1);
- break;
- case ' ':
- action(3);
- break;
- default:
- if (isAlphanum(theB)) {
- action(1);
- } else {
- action(2);
- }
- }
- break;
- default:
- switch (theB) {
- case ' ':
- if (isAlphanum(theA)) {
- action(1);
- break;
- }
- action(3);
- break;
- case '\n':
- switch (theA) {
- case '}':
- case ']':
- case ')':
- case '+':
- case '-':
- case '"':
- case '\'':
- case '`':
- action(1);
- break;
- default:
- if (isAlphanum(theA)) {
- action(1);
- } else {
- action(3);
- }
- }
- break;
- default:
- action(1);
- break;
- }
- }
- }
- }
- /* main -- Output any command line arguments as comments
- and then minify the input.
- */
- extern int
- main(int argc, char* argv[])
- {
- int i;
- for (i = 1; i < argc; i += 1) {
- fprintf(stdout, "// %s\n", argv[i]);
- }
- jsmin();
- return 0;
- }
|