Go to the documentation of this file.00001 <?php
00085 define('JSMIN_VERSION', '0.2');
00086
00092 define('EOF', FALSE);
00093
00099 define('ORD_NL', ord("\n"));
00100 define('ORD_space', ord(' '));
00101 define('ORD_cA', ord('A'));
00102 define('ORD_cZ', ord('Z'));
00103 define('ORD_a', ord('a'));
00104 define('ORD_z', ord('z'));
00105 define('ORD_0', ord('0'));
00106 define('ORD_9', ord('9'));
00107
00111
00112
00113
00114
00115 class JSMinException {
00116 }
00117
00122 class FileOpenFailedJSMinException extends JSMinException {
00123 }
00124
00129 class UnterminatedCommentJSMinException extends JSMinException {
00130 }
00131
00136 class UnterminatedStringLiteralJSMinException extends JSMinException {
00137 }
00138
00143 class UnterminatedRegExpLiteralJSMinException extends JSMinException {
00144 }
00145
00150 define ('JSMIN_ACT_FULL', 1);
00151
00156 define ('JSMIN_ACT_BUF', 2);
00157
00162 define ('JSMIN_ACT_IMM', 3);
00163
00175 class JSMin {
00176
00182 var $in;
00183
00189 var $out;
00190
00195 var $theA;
00196
00201 var $theB;
00202
00204 var $inLength = 0;
00205 var $inPos = 0;
00206 var $isString = false;
00207
00214 function isAlphaNum($c) {
00215
00216
00217
00218 $a = ord($c);
00219
00220
00221
00222
00223 return
00224 ($a >= ORD_a && $a <= ORD_z) ||
00225 ($a >= ORD_0 && $a <= ORD_9) ||
00226 ($a >= ORD_cA && $a <= ORD_cZ) ||
00227 $c === '_' || $c === '$' || $c === '\\' || $a > 126
00228 ;
00229 }
00230
00240 function get() {
00241
00242
00243
00244 if ($this->isString) {
00245 if ($this->inPos < $this->inLength) {
00246 $c = $this->in[$this->inPos];
00247 ++$this->inPos;
00248 }
00249 else {
00250 return EOF;
00251 }
00252 }
00253 else
00254 $c = $this->in->fgetc();
00255
00256
00257
00258 if ($c === "\n" || $c === EOF || ord($c) >= ORD_space) {
00259 return $c;
00260 }
00261
00262
00263
00264
00265 if ($c === "\r") {
00266 return "\n";
00267 }
00268
00269
00270
00271
00272 return ' ';
00273 }
00274
00283 function peek() {
00284
00285 if ($this->isString) {
00286 if ($this->inPos < $this->inLength) {
00287 $c = $this->in[$this->inPos];
00288 }
00289 else {
00290 return EOF;
00291 }
00292 }
00293 else {
00294
00295
00296 $c = $this->in->fgetc();
00297
00298
00299
00300 $this->in->fseek(-1, SEEK_CUR);
00301
00302
00303 }
00304
00305 return $c;
00306 }
00307
00312 function put($c)
00313 {
00314 if ($this->isString) {
00315 $this->out .= $c;
00316 }
00317 else {
00318 $this->out->fwrite($c);
00319 }
00320 }
00321
00331 function next() {
00332
00333
00334
00335 $c = $this->get();
00336
00337
00338
00339 if ($c == '/') {
00340
00341
00342
00343 switch ($this->peek()) {
00344
00345 case '/' :
00346
00347
00348
00349
00350 while (true) {
00351
00352 $c = $this->get();
00353
00354 if (ord($c) <= ORD_NL) {
00355 return $c;
00356 }
00357 }
00358
00359 case '*' :
00360
00361
00362
00363
00364 while (true) {
00365
00366
00367
00368 $c = $this->get();
00369
00370 if ($c == '*') {
00371
00372
00373
00374 if ($this->peek() == '/') {
00375
00376
00377
00378 $this->get();
00379 return ' ';
00380 }
00381 }
00382 else if ($c === EOF) {
00383
00384
00385
00386
00387 trigger_error('UnterminatedComment', E_USER_ERROR);
00388 }
00389 }
00390
00391 default :
00392
00393
00394
00395 return $c;
00396 }
00397 }
00398
00399
00400
00401 return $c;
00402 }
00403
00418 function action($action) {
00419
00420
00421
00422
00423 switch ($action) {
00424
00425 case JSMIN_ACT_FULL :
00426
00427
00428
00429 $this->put($this->theA);
00430
00431 case JSMIN_ACT_BUF :
00432
00433
00434
00435 $tmpA = $this->theA = $this->theB;
00436
00437
00438
00439
00440 if ($tmpA == '\'' || $tmpA == '"') {
00441
00442 while (true) {
00443
00444
00445
00446 $this->put($tmpA);
00447
00448
00449
00450
00451
00452 $tmpA = $this->theA = $this->get();
00453
00454 if ($tmpA == $this->theB) {
00455
00456
00457
00458 break;
00459 }
00460
00461
00462
00463 if (ord($tmpA) <= ORD_NL) {
00464
00465
00466
00467
00468 trigger_error('UnterminatedStringLiteral', E_USER_ERROR);
00469 }
00470
00471
00472
00473 if ($tmpA == '\\') {
00474
00475
00476
00477 $this->put($tmpA);
00478 $tmpA = $this->theA = $this->get();
00479 }
00480 }
00481 }
00482
00483 case JSMIN_ACT_IMM :
00484
00485
00486
00487 $this->theB = $this->next();
00488
00489
00490
00491
00492 $tmpA = $this->theA;
00493
00494 if ($this->theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) {
00495
00496
00497
00498 $this->put($tmpA);
00499 $this->put($this->theB);
00500
00501
00502
00503
00504 while (true) {
00505
00506 $tmpA = $this->theA = $this->get();
00507
00508 if ($tmpA == '/') {
00509
00510
00511
00512 break;
00513 }
00514
00515
00516
00517 if ($tmpA == '\\') {
00518
00519
00520
00521 $this->put($tmpA);
00522 $tmpA = $this->theA = $this->get();
00523 }
00524 else if (ord($tmpA) <= ORD_NL) {
00525
00526
00527
00528
00529 trigger_error('UnterminatedRegExpLiteral', E_USER_ERROR);
00530 }
00531
00532
00533
00534 $this->put($tmpA);
00535 }
00536
00537
00538
00539 $this->theB = $this->next();
00540 }
00541
00542 break;
00543 default :
00544
00545 trigger_error('Expected a JSMin::ACT_* constant in action()', E_USER_ERROR);
00546 }
00547 }
00548
00564 function minify() {
00565
00566
00567
00568 $this->theA = "\n";
00569 $this->action(JSMIN_ACT_IMM);
00570
00571
00572
00573 while ($this->theA !== EOF) {
00574
00575 switch ($this->theA) {
00576
00577 case ' ' :
00578
00579 if (JSMin::isAlphaNum($this->theB)) {
00580 $this->action(JSMIN_ACT_FULL);
00581 }
00582 else {
00583 $this->action(JSMIN_ACT_BUF);
00584 }
00585
00586 break;
00587 case "\n" :
00588
00589 switch ($this->theB) {
00590
00591 case '{' : case '[' : case '(' :
00592 case '+' : case '-' :
00593
00594 $this->action(JSMIN_ACT_FULL);
00595
00596 break;
00597 case ' ' :
00598
00599 $this->action(JSMIN_ACT_IMM);
00600
00601 break;
00602 default :
00603
00604 if (JSMin::isAlphaNum($this->theB)) {
00605 $this->action(JSMIN_ACT_FULL);
00606 }
00607 else {
00608 $this->action(JSMIN_ACT_BUF);
00609 }
00610
00611 break;
00612 }
00613
00614 break;
00615 default :
00616
00617 switch ($this->theB) {
00618
00619 case ' ' :
00620
00621 if (JSMin::isAlphaNum($this->theA)) {
00622
00623 $this->action(JSMIN_ACT_FULL);
00624 break;
00625 }
00626
00627
00628
00629 $this->action(JSMIN_ACT_IMM);
00630
00631 break;
00632 case "\n" :
00633
00634 switch ($this->theA) {
00635
00636 case '}' : case ']' : case ')' : case '+' :
00637 case '-' : case '"' : case '\'' :
00638
00639 $this->action(JSMIN_ACT_FULL);
00640
00641 break;
00642 default :
00643
00644 if (JSMin::isAlphaNum($this->theA)) {
00645 $this->action(JSMIN_ACT_FULL);
00646 }
00647 else {
00648 $this->action(JSMIN_ACT_IMM);
00649 }
00650
00651 break;
00652 }
00653
00654 break;
00655 default :
00656
00657 $this->action(JSMIN_ACT_FULL);
00658
00659 break;
00660 }
00661
00662 break;
00663 }
00664 }
00665
00666 if ($this->isString) {
00667 return $this->out;
00668
00669 }
00670 }
00671
00682 function JSMin($inFileName = '-', $outFileName = '-', $comments = NULL) {
00683 if ($outFileName === FALSE) {
00684 $this->JSMin_String($inFileName, $comments);
00685 }
00686 else {
00687 $this->JSMin_File($inFileName, $outFileName, $comments);
00688 }
00689 }
00690
00691 function JSMin_File($inFileName = '-', $outFileName = '-', $comments = NULL) {
00692
00693
00694
00695
00696 if ($inFileName == '-') $inFileName = 'php://stdin';
00697 if ($outFileName == '-') $outFileName = 'php://stdout';
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721 $this->in = fopen($inFileName, 'rb');
00722 if (!$this->in) {
00723 trigger_error('Failed to open "'.$inFileName, E_USER_ERROR);
00724 }
00725 $this->out = fopen($outFileName, 'wb');
00726 if (!$this->out) {
00727 trigger_error('Failed to open "'.$outFileName, E_USER_ERROR);
00728 }
00729
00730
00731
00732 if ($comments !== NULL) {
00733 foreach ($comments as $comm) {
00734 $this->out->fwrite('// '.str_replace("\n", " ", $comm)."\n");
00735 }
00736 }
00737
00738 }
00739
00740 function JSMin_String($inString, $comments = NULL) {
00741 $this->in = $inString;
00742 $this->out = '';
00743 $this->inLength = strlen($inString);
00744 $this->inPos = 0;
00745 $this->isString = true;
00746
00747 if ($comments !== NULL) {
00748 foreach ($comments as $comm) {
00749 $this->out .= '// '.str_replace("\n", " ", $comm)."\n";
00750 }
00751 }
00752 }
00753 }
00754
00760 ?>