Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 310 lines (281 sloc) 8.085 kb
a9b4755 @douglascrockford quasi
authored
1 /* jsmin.c
633d992 @douglascrockford confusing + and - and error
authored
2 2012-07-02
a9b4755 @douglascrockford quasi
authored
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;
633d992 @douglascrockford confusing + and - and error
authored
33 static int theX = EOF;
34 static int theY = EOF;
a9b4755 @douglascrockford quasi
authored
35
36
633d992 @douglascrockford confusing + and - and error
authored
37 static void
38 error(char* s)
39 {
40 fputs("JSMIN Error: ", stderr);
41 fputs(s, stderr);
42 fputc('\n', stderr);
43 exit(1);
44 }
45
a9b4755 @douglascrockford quasi
authored
46 /* isAlphanum -- return true if the character is a letter, digit, underscore,
47 dollar sign, or non-ASCII character.
48 */
49
50 static int
51 isAlphanum(int c)
52 {
53 return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
54 (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
55 c > 126);
56 }
57
58
59 /* get -- return the next character from stdin. Watch out for lookahead. If
60 the character is a control character, translate it to a space or
61 linefeed.
62 */
63
64 static int
65 get()
66 {
67 int c = theLookahead;
68 theLookahead = EOF;
69 if (c == EOF) {
70 c = getc(stdin);
633d992 @douglascrockford confusing + and - and error
authored
71 theY = theX;
72 theX = c;
a9b4755 @douglascrockford quasi
authored
73 }
74 if (c >= ' ' || c == '\n' || c == EOF) {
75 return c;
76 }
77 if (c == '\r') {
78 return '\n';
79 }
80 return ' ';
81 }
82
83
84 /* peek -- get the next character without getting it.
85 */
86
87 static int
88 peek()
89 {
90 theLookahead = get();
91 return theLookahead;
92 }
93
94
95 /* next -- get the next character, excluding comments. peek() is used to see
96 if a '/' is followed by a '/' or '*'.
97 */
98
99 static int
100 next()
101 {
102 int c = get();
103 if (c == '/') {
104 switch (peek()) {
105 case '/':
106 for (;;) {
107 c = get();
108 if (c <= '\n') {
109 return c;
110 }
111 }
112 case '*':
113 get();
114 for (;;) {
115 switch (get()) {
116 case '*':
117 if (peek() == '/') {
118 get();
119 return ' ';
120 }
121 break;
122 case EOF:
633d992 @douglascrockford confusing + and - and error
authored
123 error("Unterminated comment.");
a9b4755 @douglascrockford quasi
authored
124 }
125 }
126 default:
127 return c;
128 }
129 }
130 return c;
131 }
132
133
134 /* action -- do something! What you do is determined by the argument:
135 1 Output A. Copy B to A. Get the next B.
136 2 Copy B to A. Get the next B. (Delete A).
137 3 Get the next B. (Delete B).
138 action treats a string as a single character. Wow!
139 action recognizes a regular expression if it is preceded by ( or , or =.
140 */
141
142 static void
143 action(int d)
144 {
145 switch (d) {
146 case 1:
147 putc(theA, stdout);
633d992 @douglascrockford confusing + and - and error
authored
148 if (theA == theB && (theA == '+' || theA == '-') && theY != theA) {
149 putc(' ', stdout);
150 }
a9b4755 @douglascrockford quasi
authored
151 case 2:
152 theA = theB;
153 if (theA == '\'' || theA == '"' || theA == '`') {
154 for (;;) {
155 putc(theA, stdout);
156 theA = get();
157 if (theA == theB) {
158 break;
159 }
160 if (theA == '\\') {
161 putc(theA, stdout);
162 theA = get();
163 }
164 if (theA == EOF) {
633d992 @douglascrockford confusing + and - and error
authored
165 error("Unterminated string literal.");
a9b4755 @douglascrockford quasi
authored
166 }
167 }
168 }
169 case 3:
170 theB = next();
171 if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
172 theA == ':' || theA == '[' || theA == '!' ||
173 theA == '&' || theA == '|' || theA == '?' ||
174 theA == '{' || theA == '}' || theA == ';' ||
175 theA == '\n')) {
176 putc(theA, stdout);
177 putc(theB, stdout);
178 for (;;) {
179 theA = get();
180 if (theA == '[') {
181 for (;;) {
182 putc(theA, stdout);
183 theA = get();
184 if (theA == ']') {
185 break;
186 }
187 if (theA == '\\') {
188 putc(theA, stdout);
189 theA = get();
190 }
191 if (theA == EOF) {
633d992 @douglascrockford confusing + and - and error
authored
192 error("Unterminated set in Regular Expression literal.");
a9b4755 @douglascrockford quasi
authored
193 }
194 }
195 } else if (theA == '/') {
196 break;
197 } else if (theA =='\\') {
198 putc(theA, stdout);
199 theA = get();
200 }
201 if (theA == EOF) {
633d992 @douglascrockford confusing + and - and error
authored
202 error("Unterminated Regular Expression literal.");
a9b4755 @douglascrockford quasi
authored
203 }
204 putc(theA, stdout);
205 }
206 theB = next();
207 }
208 }
209 }
210
211
212 /* jsmin -- Copy the input to the output, deleting the characters which are
213 insignificant to JavaScript. Comments will be removed. Tabs will be
214 replaced with spaces. Carriage returns will be replaced with linefeeds.
215 Most spaces and linefeeds will be removed.
216 */
217
218 static void
219 jsmin()
220 {
f062955 @douglascrockford Remove byte order mark
authored
221 if (peek() == 0xEF) {
222 get();
223 get();
224 get();
225 }
a9b4755 @douglascrockford quasi
authored
226 theA = '\n';
227 action(3);
228 while (theA != EOF) {
229 switch (theA) {
230 case ' ':
231 if (isAlphanum(theB)) {
232 action(1);
233 } else {
234 action(2);
235 }
236 break;
237 case '\n':
238 switch (theB) {
239 case '{':
240 case '[':
241 case '(':
242 case '+':
243 case '-':
5ca277e @douglascrockford !~
authored
244 case '!':
245 case '~':
a9b4755 @douglascrockford quasi
authored
246 action(1);
247 break;
248 case ' ':
249 action(3);
250 break;
251 default:
252 if (isAlphanum(theB)) {
253 action(1);
254 } else {
255 action(2);
256 }
257 }
258 break;
259 default:
260 switch (theB) {
261 case ' ':
262 if (isAlphanum(theA)) {
263 action(1);
264 break;
265 }
266 action(3);
267 break;
268 case '\n':
269 switch (theA) {
270 case '}':
271 case ']':
272 case ')':
273 case '+':
274 case '-':
275 case '"':
276 case '\'':
277 case '`':
278 action(1);
279 break;
280 default:
281 if (isAlphanum(theA)) {
282 action(1);
283 } else {
284 action(3);
285 }
286 }
287 break;
288 default:
289 action(1);
290 break;
291 }
292 }
293 }
294 }
295
296
297 /* main -- Output any command line arguments as comments
298 and then minify the input.
299 */
300 extern int
301 main(int argc, char* argv[])
302 {
303 int i;
304 for (i = 1; i < argc; i += 1) {
305 fprintf(stdout, "// %s\n", argv[i]);
306 }
307 jsmin();
308 return 0;
309 }
Something went wrong with that request. Please try again.