Changeset 1771 for trunk/buildscripts/jsbuilder/jsmin.php
- Timestamp:
- 03/25/2007 07:27:59 PM (22 months ago)
- Files:
-
- 1 modified
-
trunk/buildscripts/jsbuilder/jsmin.php (modified) (36 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/buildscripts/jsbuilder/jsmin.php
r990 r1771 1 1 <?php 2 3 /** 4 * JSMin.php (for PHP 5) 2 /** 3 * JSMin_lib.php (for PHP 4, 5) 5 4 * 6 5 * PHP adaptation of JSMin, published by Douglas Crockford as jsmin.c, also based … … 38 37 * @copyright No new copyright ; please keep above and following information. 39 38 * @author David Holmes <dholmes@cfdsoftware.net> of CFD Labs, France 40 * @version 0.1 (PHP translation) 2006-04-11 39 * @author Gaetano Giunta 40 * @version $Id: $ 41 41 * 42 42 * Please note, this is a brutal and simple conversion : it could undoubtedly be … … 44 44 * features. 45 45 * 46 * PHP 5 is required because OO style of programming is used, as well as classes 47 * from the Standard PHP Library (SPL). 46 * Exceptions and all PHP 5 - only features ahve been removed for compat with PHP 4 48 47 * 49 48 * Note : whereas jsmin.c works specifically with the standard input and output … … 67 66 * 68 67 * See JSMin.php -h (or --help) for command-line documentation. 68 * 69 * NEW AND IMPROVED in version 0.2: 70 * to take advantage of this file in your own code, you can do the following: 71 * 72 * define('JSMIN_AS_LIB', true); // prevents auto-run on include 73 * include('jsmin.php'); 74 * // the JSMin class now works on php strings, too 75 * $jsMin = new JSMin(file_get_contents('e:/htdocs/awstats_misc_tracker.js'), false); 76 * // in that case, the modifies string is returned by minify(): 77 * $out = $jsMin->minify(); 78 * 69 79 */ 70 80 … … 73 83 */ 74 84 75 define(' VERSION', '0.1');85 define('JSMIN_VERSION', '0.2'); 76 86 77 87 /** … … 99 109 * Generic exception class related to JSMin. 100 110 */ 101 111 /* 102 112 class JSMinException extends Exception { 103 113 } 114 */ 115 class JSMinException { 116 } 104 117 105 118 /** … … 132 145 133 146 /** 147 * Constant describing an {@link action()} : Output A. Copy B to A. Get the next B. 148 */ 149 150 define ('JSMIN_ACT_FULL', 1); 151 152 /** 153 * Constant describing an {@link action()} : Copy B to A. Get the next B. (Delete A). 154 */ 155 156 define ('JSMIN_ACT_BUF', 2); 157 158 /** 159 * Constant describing an {@link action()} : Get the next B. (Delete B). 160 */ 161 162 define ('JSMIN_ACT_IMM', 3); 163 164 /** 134 165 * Main JSMin application class. 135 166 * … … 137 168 * 138 169 * $jsMin = new JSMin(...input..., ...output...); 139 * $jsMin ->minify();170 * $jsMin->minify(); 140 171 * 141 172 * Do not specify input and/or output (or default to '-') to use stdin and/or stdout. … … 145 176 146 177 /** 147 * Constant describing an {@link action()} : Output A. Copy B to A. Get the next B.148 */149 150 const ACT_FULL = 1;151 152 /**153 * Constant describing an {@link action()} : Copy B to A. Get the next B. (Delete A).154 */155 156 const ACT_BUF = 2;157 158 /**159 * Constant describing an {@link action()} : Get the next B. (Delete B).160 */161 162 const ACT_IMM = 3;163 164 /**165 178 * The input stream, from which to read a JS file to minimize. Obtained by fopen(). 166 * @var SplFileObject167 * /168 169 private$in;179 * NB: might be a string instead of a stream 180 * @var SplFileObject | string 181 */ 182 var $in; 170 183 171 184 /** 172 185 * The output stream, in which to write the minimized JS file. Obtained by fopen(). 173 * @var SplFileObject174 * /175 176 private$out;186 * NB: might be a string instead of a stream 187 * @var SplFileObject | string 188 */ 189 var $out; 177 190 178 191 /** … … 180 193 * @var string 181 194 */ 182 183 private $theA; 195 var $theA; 184 196 185 197 /** … … 187 199 * @var string 188 200 */ 189 190 private $theB; 201 var $theB; 202 203 /** variables used for string-based parsing **/ 204 var $inLength = 0; 205 var $inPos = 0; 206 var $isString = false; 191 207 192 208 /** … … 196 212 * @return boolean Whether the char is a letter, digit, underscore, dollar, backslash, or non-ASCII. 197 213 */ 198 199 private static function isAlphaNum($c) { 214 function isAlphaNum($c) { 200 215 201 216 // Get ASCII value of character for C-like comparisons … … 223 238 * @see peek() 224 239 */ 225 226 private function get() { 240 function get() { 227 241 228 242 // Get next input character and advance position in file 229 230 $c = $this -> in -> fgetc(); 243 //var_dump($this); 244 if ($this->isString) { 245 if ($this->inPos < $this->inLength) { 246 $c = $this->in[$this->inPos]; 247 ++$this->inPos; 248 } 249 else { 250 return EOF; 251 } 252 } 253 else 254 $c = $this->in->fgetc(); 231 255 232 256 // Test for non-problematic characters … … 257 281 * @see get() 258 282 */ 259 260 private function peek() { 261 262 // Get next input character 263 264 $c = $this -> in -> fgetc(); 265 266 // Regress position in file 267 268 $this -> in -> fseek(-1, SEEK_CUR); 269 270 // Return character obtained 283 function peek() { 284 285 if ($this->isString) { 286 if ($this->inPos < $this->inLength) { 287 $c = $this->in[$this->inPos]; 288 } 289 else { 290 return EOF; 291 } 292 } 293 else { 294 // Get next input character 295 296 $c = $this->in->fgetc(); 297 298 // Regress position in file 299 300 $this->in->fseek(-1, SEEK_CUR); 301 302 // Return character obtained 303 } 271 304 272 305 return $c; 273 306 } 307 308 /** 309 * Adds a char to the output steram / string 310 * @see $out 311 */ 312 function put($c) 313 { 314 if ($this->isString) { 315 $this->out .= $c; 316 } 317 else { 318 $this->out->fwrite($c); 319 } 320 } 274 321 275 322 /** … … 282 329 * @see $in 283 330 */ 284 285 private function next() { 331 function next() { 286 332 287 333 // Get next char from input, translated if necessary 288 334 289 $c = $this ->get();335 $c = $this->get(); 290 336 291 337 // Check comment possibility … … 295 341 // Look ahead : a comment is two slashes or slashes followed by asterisk (to be closed) 296 342 297 switch ($this ->peek()) {343 switch ($this->peek()) { 298 344 299 345 case '/' : 300 346 301 347 // Comment is up to the end of the line 302 // TOTEST : simple $this -> in ->fgets()348 // TOTEST : simple $this->in->fgets() 303 349 304 350 while (true) { 305 351 306 $c = $this ->get();352 $c = $this->get(); 307 353 308 354 if (ord($c) <= ORD_NL) { … … 320 366 // N.B. not using switch() because of having to test EOF with === 321 367 322 $c = $this ->get();368 $c = $this->get(); 323 369 324 370 if ($c == '*') { … … 326 372 // Comment termination if the char ahead is a slash 327 373 328 if ($this ->peek() == '/') {374 if ($this->peek() == '/') { 329 375 330 376 // Advance again and make into a single space 331 377 332 $this ->get();378 $this->get(); 333 379 return ' '; 334 380 } … … 338 384 // Whoopsie 339 385 340 throw new UnterminatedCommentJSMinException(); 386 //throw new UnterminatedCommentJSMinException(); 387 trigger_error('UnterminatedComment', E_USER_ERROR); 341 388 } 342 389 } … … 360 407 * The action to perform is determined by the argument : 361 408 * 362 * JSMin ::ACT_FULL : Output A. Copy B to A. Get the next B.363 * JSMin ::ACT_BUF : Copy B to A. Get the next B. (Delete A).364 * JSMin ::ACT_IMM : Get the next B. (Delete B).409 * JSMin::ACT_FULL : Output A. Copy B to A. Get the next B. 410 * JSMin::ACT_BUF : Copy B to A. Get the next B. (Delete A). 411 * JSMin::ACT_IMM : Get the next B. (Delete B). 365 412 * 366 413 * A string is treated as a single character. Also, regular expressions are recognized if preceded 367 414 * by '(', ',' or '='. 368 415 * 369 * @param int $action The action to perform : one of the JSMin :: ACT_* constants. 370 */ 371 372 private function action($action) { 416 * @param int $action The action to perform : one of the JSMin::ACT_* constants. 417 */ 418 function action($action) { 373 419 374 420 // Choice of possible actions … … 377 423 switch ($action) { 378 424 379 case self ::ACT_FULL :425 case JSMIN_ACT_FULL : 380 426 381 427 // Write A to output, then fall through 382 428 383 $this -> out -> fwrite($this ->theA);384 385 case self ::ACT_BUF : // N.B. possible fallthrough from above429 $this->put($this->theA); 430 431 case JSMIN_ACT_BUF : // N.B. possible fallthrough from above 386 432 387 433 // Copy B to A 388 434 389 $tmpA = $this -> theA = $this ->theB;435 $tmpA = $this->theA = $this->theB; 390 436 391 437 // Treating a string as a single char : outputting it whole … … 398 444 // Output string contents 399 445 400 $this -> out -> fwrite($tmpA);446 $this->put($tmpA); 401 447 402 448 // Get next character, watching out for termination of the current string, … … 404 450 // (upon which the following char is directly output to serve the escape mechanism) 405 451 406 $tmpA = $this -> theA = $this ->get();407 408 if ($tmpA == $this ->theB) {452 $tmpA = $this->theA = $this->get(); 453 454 if ($tmpA == $this->theB) { 409 455 410 456 // String terminated … … 419 465 // Whoopsie 420 466 421 throw new UnterminatedStringLiteralJSMinException(); 467 //throw new UnterminatedStringLiteralJSMinException(); 468 trigger_error('UnterminatedStringLiteral', E_USER_ERROR); 422 469 } 423 470 … … 428 475 // Escape next char immediately 429 476 430 $this -> out -> fwrite($tmpA);431 $tmpA = $this -> theA = $this ->get();477 $this->put($tmpA); 478 $tmpA = $this->theA = $this->get(); 432 479 } 433 480 } 434 481 } 435 482 436 case self ::ACT_IMM : // N.B. possible fallthrough from above483 case JSMIN_ACT_IMM : // N.B. possible fallthrough from above 437 484 438 485 // Get the next B 439 486 440 $this -> theB = $this ->next();487 $this->theB = $this->next(); 441 488 442 489 // Special case of recognising regular expressions (beginning with /) that are 443 490 // preceded by '(', ',' or '=' 444 491 445 $tmpA = $this ->theA;446 447 if ($this ->theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) {492 $tmpA = $this->theA; 493 494 if ($this->theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) { 448 495 449 496 // Output the two successive chars 450 497 451 $this -> out -> fwrite($tmpA);452 $this -> out -> fwrite($this ->theB);498 $this->put($tmpA); 499 $this->put($this->theB); 453 500 454 501 // Look for the end of the RE literal, watching out for escaped chars or a control / … … 457 504 while (true) { 458 505 459 $tmpA = $this -> theA = $this ->get();506 $tmpA = $this->theA = $this->get(); 460 507 461 508 if ($tmpA == '/') { … … 472 519 // Escape next char immediately 473 520 474 $this -> out -> fwrite($tmpA);475 $tmpA = $this -> theA = $this ->get();521 $this->put($tmpA); 522 $tmpA = $this->theA = $this->get(); 476 523 } 477 524 else if (ord($tmpA) <= ORD_NL) { … … 479 526 // Whoopsie 480 527 481 throw new UnterminatedRegExpLiteralJSMinException(); 528 //throw new UnterminatedRegExpLiteralJSMinException(); 529 trigger_error('UnterminatedRegExpLiteral', E_USER_ERROR); 482 530 } 483 531 484 532 // Output RE characters 485 533 486 $this -> out -> fwrite($tmpA);534 $this->put($tmpA); 487 535 } 488 536 489 537 // Move forward after the RE literal 490 538 491 $this -> theB = $this ->next();539 $this->theB = $this->next(); 492 540 } 493 541 494 542 break; 495 default : throw new JSMinException('Expected a JSMin :: ACT_* constant in action().'); 543 default : 544 //throw new JSMinException('Expected a JSMin::ACT_* constant in action().'); 545 trigger_error('Expected a JSMin::ACT_* constant in action()', E_USER_ERROR); 496 546 } 497 547 } … … 501 551 * 502 552 * The code is read from the input stream, and its minified version is written to the output one. 553 * In case input is a string, minified vesrions is also returned by this function as string. 503 554 * That is : characters which are insignificant to JavaScript are removed, as well as comments ; 504 555 * tabs are replaced with spaces ; carriage returns are replaced with linefeeds, and finally most … … 508 559 * the name of this class. 509 560 * 510 * @see __construct()511 * /512 513 publicfunction minify() {561 * @see JSMin() 562 * @return null | string 563 */ 564 function minify() { 514 565 515 566 // Initialize A and run the first (minimal) action 516 567 517 $this ->theA = "\n";518 $this -> action(self ::ACT_IMM);568 $this->theA = "\n"; 569 $this->action(JSMIN_ACT_IMM); 519 570 520 571 // Proceed all the way to the end of the input file 521 572 522 while ($this ->theA !== EOF) {523 524 switch ($this ->theA) {573 while ($this->theA !== EOF) { 574 575 switch ($this->theA) { 525 576 526 577 case ' ' : 527 578 528 if ( self :: isAlphaNum($this ->theB)) {529 $this -> action(self ::ACT_FULL);579 if (JSMin::isAlphaNum($this->theB)) { 580 $this->action(JSMIN_ACT_FULL); 530 581 } 531 582 else { 532 $this -> action(self ::ACT_BUF);583 $this->action(JSMIN_ACT_BUF); 533 584 } 534 585 … … 536 587 case "\n" : 537 588 538 switch ($this ->theB) {589 switch ($this->theB) { 539 590 540 591 case '{' : case '[' : case '(' : 541 592 case '+' : case '-' : 542 593 543 $this -> action(self ::ACT_FULL);594 $this->action(JSMIN_ACT_FULL); 544 595 545 596 break; 546 597 case ' ' : 547 598 548 $this -> action(self ::ACT_IMM);599 $this->action(JSMIN_ACT_IMM); 549 600 550 601 break; 551 602 default : 552 603 553 if ( self :: isAlphaNum($this ->theB)) {554 $this -> action(self ::ACT_FULL);604 if (JSMin::isAlphaNum($this->theB)) { 605 $this->action(JSMIN_ACT_FULL); 555 606 } 556 607 else { 557 $this -> action(self ::ACT_BUF);608 $this->action(JSMIN_ACT_BUF); 558 609 } 559 610 … … 564 615 default : 565 616 566 switch ($this ->theB) {617 switch ($this->theB) { 567 618 568 619 case ' ' : 569 620 570 if ( self :: isAlphaNum($this ->theA)) {571 572 $this -> action(self ::ACT_FULL);621 if (JSMin::isAlphaNum($this->theA)) { 622 623 $this->action(JSMIN_ACT_FULL); 573 624 break; 574 625 } … … 576 627 // else 577 628 578 $this -> action(self ::ACT_IMM);629 $this->action(JSMIN_ACT_IMM); 579 630 580 631 break; 581 632 case "\n" : 582 633 583 switch ($this ->theA) {634 switch ($this->theA) { 584 635 585 636 case '}' : case ']' : case ')' : case '+' : 586 637 case '-' : case '"' : case '\'' : 587 638 588 $this -> action(self ::ACT_FULL);639 $this->action(JSMIN_ACT_FULL); 589 640 590 641 break; 591 642 default : 592 643 593 if ( self :: isAlphaNum($this ->theA)) {594 $this -> action(self ::ACT_FULL);644 if (JSMin::isAlphaNum($this->theA)) { 645 $this->action(JSMIN_ACT_FULL); 595 646 } 596 647 else { 597 $this -> action(self ::ACT_IMM);648 $this->action(JSMIN_ACT_IMM); 598 649 } 599 650 … … 604 655 default : 605 656 606 $this -> action(self ::ACT_FULL);657 $this->action(JSMIN_ACT_FULL); 607 658 608 659 break; … … 612 663 } 613 664 } 665 666 if ($this->isString) { 667 return $this->out; 668 669 } 614 670
