Show
Ignore:
Timestamp:
03/25/2007 07:27:59 PM (22 months ago)
Author:
xue
Message:

merge from 3.0 branch till 1769.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/buildscripts/jsbuilder/jsmin.php

    r990 r1771  
    11<?php 
    2  
    3 /** 
    4 * JSMin.php (for PHP 5) 
     2/** 
     3* JSMin_lib.php (for PHP 4, 5) 
    54* 
    65* PHP adaptation of JSMin, published by Douglas Crockford as jsmin.c, also based 
     
    3837* @copyright   No new copyright ; please keep above and following information. 
    3938* @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: $ 
    4141* 
    4242* Please note, this is a brutal and simple conversion : it could undoubtedly be 
     
    4444* features. 
    4545* 
    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 
    4847* 
    4948* Note : whereas jsmin.c works specifically with the standard input and output 
     
    6766* 
    6867* 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* 
    6979*/ 
    7080 
     
    7383*/ 
    7484 
    75 define('VERSION', '0.1'); 
     85define('JSMIN_VERSION', '0.2'); 
    7686 
    7787/** 
     
    99109* Generic exception class related to JSMin. 
    100110*/ 
    101  
     111/* 
    102112class JSMinException extends Exception { 
    103113} 
     114*/ 
     115class JSMinException { 
     116} 
    104117 
    105118/** 
     
    132145 
    133146/** 
     147 * Constant describing an {@link action()} : Output A. Copy B to A. Get the next B. 
     148 */ 
     149 
     150define ('JSMIN_ACT_FULL', 1); 
     151 
     152/** 
     153 * Constant describing an {@link action()} : Copy B to A. Get the next B. (Delete A). 
     154 */ 
     155 
     156define ('JSMIN_ACT_BUF', 2); 
     157 
     158/** 
     159 * Constant describing an {@link action()} : Get the next B. (Delete B). 
     160 */ 
     161 
     162define ('JSMIN_ACT_IMM', 3); 
     163 
     164/** 
    134165* Main JSMin application class. 
    135166* 
     
    137168* 
    138169* $jsMin = new JSMin(...input..., ...output...); 
    139 * $jsMin -> minify(); 
     170* $jsMin->minify(); 
    140171* 
    141172* Do not specify input and/or output (or default to '-') to use stdin and/or stdout. 
     
    145176 
    146177    /** 
    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     /** 
    165178     * The input stream, from which to read a JS file to minimize. Obtained by fopen(). 
    166      * @var SplFileObject 
    167      */ 
    168  
    169     private $in; 
     179     * NB: might be a string instead of a stream 
     180     * @var SplFileObject | string 
     181     */ 
     182    var $in; 
    170183 
    171184    /** 
    172185     * The output stream, in which to write the minimized JS file. Obtained by fopen(). 
    173      * @var SplFileObject 
    174      */ 
    175  
    176     private $out; 
     186     * NB: might be a string instead of a stream 
     187     * @var SplFileObject | string 
     188     */ 
     189    var $out; 
    177190 
    178191    /** 
     
    180193     * @var string 
    181194     */ 
    182  
    183     private $theA; 
     195    var $theA; 
    184196 
    185197    /** 
     
    187199     * @var string 
    188200     */ 
    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; 
    191207 
    192208    /** 
     
    196212     * @return  boolean     Whether the char is a letter, digit, underscore, dollar, backslash, or non-ASCII. 
    197213     */ 
    198  
    199     private static function isAlphaNum($c) { 
     214    function isAlphaNum($c) { 
    200215 
    201216        // Get ASCII value of character for C-like comparisons 
     
    223238     * @see     peek() 
    224239     */ 
    225  
    226     private function get() { 
     240    function get() { 
    227241 
    228242        // 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(); 
    231255 
    232256        // Test for non-problematic characters 
     
    257281     * @see     get() 
    258282     */ 
    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            } 
    271304 
    272305        return $c; 
    273306    } 
     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        } 
    274321 
    275322    /** 
     
    282329     * @see     $in 
    283330     */ 
    284  
    285     private function next() { 
     331    function next() { 
    286332 
    287333        // Get next char from input, translated if necessary 
    288334 
    289         $c = $this -> get(); 
     335        $c = $this->get(); 
    290336 
    291337        // Check comment possibility 
     
    295341            // Look ahead : a comment is two slashes or slashes followed by asterisk (to be closed) 
    296342 
    297             switch ($this -> peek()) { 
     343            switch ($this->peek()) { 
    298344 
    299345                case '/' : 
    300346 
    301347                    // Comment is up to the end of the line 
    302                     // TOTEST : simple $this -> in -> fgets() 
     348                    // TOTEST : simple $this->in->fgets() 
    303349 
    304350                    while (true) { 
    305351 
    306                         $c = $this -> get(); 
     352                        $c = $this->get(); 
    307353 
    308354                        if (ord($c) <= ORD_NL) { 
     
    320366                        // N.B. not using switch() because of having to test EOF with === 
    321367 
    322                         $c = $this -> get(); 
     368                        $c = $this->get(); 
    323369 
    324370                        if ($c == '*') { 
     
    326372                            // Comment termination if the char ahead is a slash 
    327373 
    328                             if ($this -> peek() == '/') { 
     374                            if ($this->peek() == '/') { 
    329375 
    330376                                // Advance again and make into a single space 
    331377 
    332                                 $this -> get(); 
     378                                $this->get(); 
    333379                                return ' '; 
    334380                            } 
     
    338384                            // Whoopsie 
    339385 
    340                             throw new UnterminatedCommentJSMinException(); 
     386                            //throw new UnterminatedCommentJSMinException(); 
     387                            trigger_error('UnterminatedComment', E_USER_ERROR); 
    341388                        } 
    342389                    } 
     
    360407     * The action to perform is determined by the argument : 
    361408     * 
    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). 
    365412     * 
    366413     * A string is treated as a single character. Also, regular expressions are recognized if preceded 
    367414     * by '(', ',' or '='. 
    368415     * 
    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) { 
    373419 
    374420        // Choice of possible actions 
     
    377423        switch ($action) { 
    378424 
    379             case self :: ACT_FULL : 
     425            case JSMIN_ACT_FULL : 
    380426 
    381427                // Write A to output, then fall through 
    382428 
    383                 $this -> out -> fwrite($this -> theA); 
    384  
    385             case self :: ACT_BUF : // N.B. possible fallthrough from above 
     429                $this->put($this->theA); 
     430 
     431            case JSMIN_ACT_BUF : // N.B. possible fallthrough from above 
    386432 
    387433                // Copy B to A 
    388434 
    389                 $tmpA = $this -> theA = $this -> theB; 
     435                $tmpA = $this->theA = $this->theB; 
    390436 
    391437                // Treating a string as a single char : outputting it whole 
     
    398444                        // Output string contents 
    399445 
    400                         $this -> out -> fwrite($tmpA); 
     446                        $this->put($tmpA); 
    401447 
    402448                        // Get next character, watching out for termination of the current string, 
     
    404450                        // (upon which the following char is directly output to serve the escape mechanism) 
    405451 
    406                         $tmpA = $this -> theA = $this -> get(); 
    407  
    408                         if ($tmpA == $this -> theB) { 
     452                        $tmpA = $this->theA = $this->get(); 
     453 
     454                        if ($tmpA == $this->theB) { 
    409455 
    410456                            // String terminated 
     
    419465                            // Whoopsie 
    420466 
    421                             throw new UnterminatedStringLiteralJSMinException(); 
     467                            //throw new UnterminatedStringLiteralJSMinException(); 
     468                            trigger_error('UnterminatedStringLiteral', E_USER_ERROR); 
    422469                        } 
    423470 
     
    428475                            // Escape next char immediately 
    429476 
    430                             $this -> out -> fwrite($tmpA); 
    431                             $tmpA = $this -> theA = $this -> get(); 
     477                            $this->put($tmpA); 
     478                            $tmpA = $this->theA = $this->get(); 
    432479                        } 
    433480                    } 
    434481                } 
    435482 
    436             case self :: ACT_IMM : // N.B. possible fallthrough from above 
     483            case JSMIN_ACT_IMM : // N.B. possible fallthrough from above 
    437484 
    438485                // Get the next B 
    439486 
    440                 $this -> theB = $this -> next(); 
     487                $this->theB = $this->next(); 
    441488 
    442489                // Special case of recognising regular expressions (beginning with /) that are 
    443490                // preceded by '(', ',' or '=' 
    444491 
    445                 $tmpA = $this -> theA; 
    446  
    447                 if ($this -> theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) { 
     492                $tmpA = $this->theA; 
     493 
     494                if ($this->theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) { 
    448495 
    449496                    // Output the two successive chars 
    450497 
    451                     $this -> out -> fwrite($tmpA); 
    452                     $this -> out -> fwrite($this -> theB); 
     498                    $this->put($tmpA); 
     499                    $this->put($this->theB); 
    453500 
    454501                    // Look for the end of the RE literal, watching out for escaped chars or a control / 
     
    457504                    while (true) { 
    458505 
    459                         $tmpA = $this -> theA = $this -> get(); 
     506                        $tmpA = $this->theA = $this->get(); 
    460507 
    461508                        if ($tmpA == '/') { 
     
    472519                            // Escape next char immediately 
    473520 
    474                             $this -> out -> fwrite($tmpA); 
    475                             $tmpA = $this -> theA = $this -> get(); 
     521                            $this->put($tmpA); 
     522                            $tmpA = $this->theA = $this->get(); 
    476523                        } 
    477524                        else if (ord($tmpA) <= ORD_NL) { 
     
    479526                            // Whoopsie 
    480527 
    481                             throw new UnterminatedRegExpLiteralJSMinException(); 
     528                            //throw new UnterminatedRegExpLiteralJSMinException(); 
     529                            trigger_error('UnterminatedRegExpLiteral', E_USER_ERROR); 
    482530                        } 
    483531 
    484532                        // Output RE characters 
    485533 
    486                         $this -> out -> fwrite($tmpA); 
     534                        $this->put($tmpA); 
    487535                    } 
    488536 
    489537                    // Move forward after the RE literal 
    490538 
    491                     $this -> theB = $this -> next(); 
     539                    $this->theB = $this->next(); 
    492540                } 
    493541 
    494542            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); 
    496546        } 
    497547    } 
     
    501551     * 
    502552     * 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. 
    503554     * That is : characters which are insignificant to JavaScript are removed, as well as comments ; 
    504555     * tabs are replaced with spaces ; carriage returns are replaced with linefeeds, and finally most 
     
    508559     * the name of this class. 
    509560     * 
    510      * @see     __construct() 
    511      */ 
    512  
    513     public function minify() { 
     561     * @see     JSMin() 
     562     * @return null | string 
     563     */ 
     564    function minify() { 
    514565 
    515566        // Initialize A and run the first (minimal) action 
    516567 
    517         $this -> theA = "\n"; 
    518         $this -> action(self :: ACT_IMM); 
     568        $this->theA = "\n"; 
     569        $this->action(JSMIN_ACT_IMM); 
    519570 
    520571        // Proceed all the way to the end of the input file 
    521572 
    522         while ($this -> theA !== EOF) { 
    523  
    524             switch ($this -> theA) { 
     573        while ($this->theA !== EOF) { 
     574 
     575            switch ($this->theA) { 
    525576 
    526577                case ' ' : 
    527578 
    528                     if (self :: isAlphaNum($this -> theB)) { 
    529                         $this -> action(self :: ACT_FULL); 
     579                    if (JSMin::isAlphaNum($this->theB)) { 
     580                        $this->action(JSMIN_ACT_FULL); 
    530581                    } 
    531582                    else { 
    532                         $this -> action(self :: ACT_BUF); 
     583                        $this->action(JSMIN_ACT_BUF); 
    533584                    } 
    534585 
     
    536587                case "\n" : 
    537588 
    538                     switch ($this -> theB) { 
     589                    switch ($this->theB) { 
    539590 
    540591                        case '{' : case '[' : case '(' : 
    541592                        case '+' : case '-' : 
    542593 
    543                             $this -> action(self :: ACT_FULL); 
     594                            $this->action(JSMIN_ACT_FULL); 
    544595 
    545596                        break; 
    546597                        case ' ' : 
    547598 
    548                             $this -> action(self :: ACT_IMM); 
     599                            $this->action(JSMIN_ACT_IMM); 
    549600 
    550601                        break; 
    551602                        default : 
    552603 
    553                             if (self :: isAlphaNum($this -> theB)) { 
    554                                 $this -> action(self :: ACT_FULL); 
     604                            if (JSMin::isAlphaNum($this->theB)) { 
     605                                $this->action(JSMIN_ACT_FULL); 
    555606                            } 
    556607                            else { 
    557                                 $this -> action(self :: ACT_BUF); 
     608                                $this->action(JSMIN_ACT_BUF); 
    558609                            } 
    559610 
     
    564615                default : 
    565616 
    566                     switch ($this -> theB) { 
     617                    switch ($this->theB) { 
    567618 
    568619                        case ' ' : 
    569620 
    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); 
    573624                                break; 
    574625                            } 
     
    576627                            // else 
    577628 
    578                             $this -> action(self :: ACT_IMM); 
     629                            $this->action(JSMIN_ACT_IMM); 
    579630 
    580631                        break; 
    581632                        case "\n" : 
    582633 
    583                             switch ($this -> theA) { 
     634                            switch ($this->theA) { 
    584635 
    585636                                case '}' : case ']' : case ')' : case '+' : 
    586637                                case '-' : case '"' : case '\'' : 
    587638 
    588                                     $this -> action(self :: ACT_FULL); 
     639                                    $this->action(JSMIN_ACT_FULL); 
    589640 
    590641                                break; 
    591642                                default : 
    592643 
    593                                     if (self :: isAlphaNum($this -> theA)) { 
    594                                         $this -> action(self :: ACT_FULL); 
     644                                    if (JSMin::isAlphaNum($this->theA)) { 
     645                                        $this->action(JSMIN_ACT_FULL); 
    595646                                    } 
    596647                                    else { 
    597                                         $this -> action(self :: ACT_IMM); 
     648                                        $this->action(JSMIN_ACT_IMM); 
    598649                                    } 
    599650 
     
    604655                        default : 
    605656 
    606                             $this -> action(self :: ACT_FULL); 
     657                            $this->action(JSMIN_ACT_FULL); 
    607658 
    608659                        break; 
     
    612663            } 
    613664        } 
     665 
     666            if ($this->isString) { 
     667                    return $this->out; 
     668 
     669            } 
    614670