]> dev.renevier.net Git - syp.git/blob - openlayers/tools/jsmin.c
initial commit
[syp.git] / openlayers / tools / jsmin.c
1 /* jsmin.c
2    2006-05-04
3
4 Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of
7 this software and associated documentation files (the "Software"), to deal in
8 the Software without restriction, including without limitation the rights to
9 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 of the Software, and to permit persons to whom the Software is furnished to do
11 so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 The Software shall be used for Good, not Evil.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 static int   theA;
31 static int   theB;
32 static int   theLookahead = EOF;
33
34
35 /* isAlphanum -- return true if the character is a letter, digit, underscore,
36         dollar sign, or non-ASCII character.
37 */
38
39 static int
40 isAlphanum(int c)
41 {
42     return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
43         (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
44         c > 126);
45 }
46
47
48 /* get -- return the next character from stdin. Watch out for lookahead. If
49         the character is a control character, translate it to a space or
50         linefeed.
51 */
52
53 static int
54 get()
55 {
56     int c = theLookahead;
57     theLookahead = EOF;
58     if (c == EOF) {
59         c = getc(stdin);
60     }
61     if (c >= ' ' || c == '\n' || c == EOF) {
62         return c;
63     }
64     if (c == '\r') {
65         return '\n';
66     }
67     return ' ';
68 }
69
70
71 /* peek -- get the next character without getting it.
72 */
73
74 static int
75 peek()
76 {
77     theLookahead = get();
78     return theLookahead;
79 }
80
81
82 /* next -- get the next character, excluding comments. peek() is used to see
83         if a '/' is followed by a '/' or '*'.
84 */
85
86 static int
87 next()
88 {
89     int c = get();
90     if  (c == '/') {
91         switch (peek()) {
92         case '/':
93             for (;;) {
94                 c = get();
95                 if (c <= '\n') {
96                     return c;
97                 }
98             }
99         case '*':
100             get();
101             for (;;) {
102                 switch (get()) {
103                 case '*':
104                     if (peek() == '/') {
105                         get();
106                         return ' ';
107                     }
108                     break;
109                 case EOF:
110                     fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
111                     exit(1);
112                 }
113             }
114         default:
115             return c;
116         }
117     }
118     return c;
119 }
120
121
122 /* action -- do something! What you do is determined by the argument:
123         1   Output A. Copy B to A. Get the next B.
124         2   Copy B to A. Get the next B. (Delete A).
125         3   Get the next B. (Delete B).
126    action treats a string as a single character. Wow!
127    action recognizes a regular expression if it is preceded by ( or , or =.
128 */
129
130 static void
131 action(int d)
132 {
133     switch (d) {
134     case 1:
135         putc(theA, stdout);
136     case 2:
137         theA = theB;
138         if (theA == '\'' || theA == '"') {
139             for (;;) {
140                 putc(theA, stdout);
141                 theA = get();
142                 if (theA == theB) {
143                     break;
144                 }
145                 if (theA <= '\n') {
146                     fprintf(stderr,
147 "Error: JSMIN unterminated string literal: %c\n", theA);
148                     exit(1);
149                 }
150                 if (theA == '\\') {
151                     putc(theA, stdout);
152                     theA = get();
153                 }
154             }
155         }
156     case 3:
157         theB = next();
158         if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
159                 theA == ':' || theA == '[' || theA == '!' || theA == '&' || 
160                 theA == '|')) {
161             putc(theA, stdout);
162             putc(theB, stdout);
163             for (;;) {
164                 theA = get();
165                 if (theA == '/') {
166                     break;
167                 } else if (theA =='\\') {
168                     putc(theA, stdout);
169                     theA = get();
170                 } else if (theA <= '\n') {
171                     fprintf(stderr,
172 "Error: JSMIN unterminated Regular Expression literal.\n", theA);
173                     exit(1);
174                 }
175                 putc(theA, stdout);
176             }
177             theB = next();
178         }
179     }
180 }
181
182
183 /* jsmin -- Copy the input to the output, deleting the characters which are
184         insignificant to JavaScript. Comments will be removed. Tabs will be
185         replaced with spaces. Carriage returns will be replaced with linefeeds.
186         Most spaces and linefeeds will be removed.
187 */
188
189 static void
190 jsmin()
191 {
192     theA = '\n';
193     action(3);
194     while (theA != EOF) {
195         switch (theA) {
196         case ' ':
197             if (isAlphanum(theB)) {
198                 action(1);
199             } else {
200                 action(2);
201             }
202             break;
203         case '\n':
204             switch (theB) {
205             case '{':
206             case '[':
207             case '(':
208             case '+':
209             case '-':
210                 action(1);
211                 break;
212             case ' ':
213                 action(3);
214                 break;
215             default:
216                 if (isAlphanum(theB)) {
217                     action(1);
218                 } else {
219                     action(2);
220                 }
221             }
222             break;
223         default:
224             switch (theB) {
225             case ' ':
226                 if (isAlphanum(theA)) {
227                     action(1);
228                     break;
229                 }
230                 action(3);
231                 break;
232             case '\n':
233                 switch (theA) {
234                 case '}':
235                 case ']':
236                 case ')':
237                 case '+':
238                 case '-':
239                 case '"':
240                 case '\'':
241                     action(1);
242                     break;
243                 default:
244                     if (isAlphanum(theA)) {
245                         action(1);
246                     } else {
247                         action(3);
248                     }
249                 }
250                 break;
251             default:
252                 action(1);
253                 break;
254             }
255         }
256     }
257 }
258
259
260 /* main -- Output any command line arguments as comments
261         and then minify the input.
262 */
263 extern int
264 main(int argc, char* argv[])
265 {
266     int i;
267     for (i = 1; i < argc; i += 1) {
268         fprintf(stdout, "// %s\n", argv[i]);
269     }
270     jsmin();
271     return 0;
272 }