All pastes #253043 Raw Edit

Miscellany

public text v1 · immutable
#253043 ·published 2006-11-20 07:11 UTC
rendered paste body
<?php
function something(info) {
$script = new mirc_script(info);
$script->highlight();
return $script->get_script();
}
class mirc_script {
  private $data = array();
  public $chars = array();
  
  // By specifying TRUE for $beautify here you can save a bit a processing time rather than call the beautify method later
  public function __construct($script = NULL,$beautify = FALSE) {
    if ($beautify && $script !== NULL) {
        $this->beautify($script);
    } else {
      $this->script = $script;
    }
  }
  
  // Attempt to beautify the script a bit
    public function beautify($input = NULL) {
        // Beautify the script
        $script = ($input === NULL ? $this->script : $input);
        
        // Break apart commands separated by |
        $script = preg_replace('/\s+\|\s+/',"\n",$script);
        
        // Put newlines before } and after {
        $script = preg_replace('/\s+\}\s*(?:\s|$)/',"\n}\n",$script);
        $script = preg_replace('/(?<=\s|^)\{\s+/',"{\n",$script);
        
        // Put () around some if conditions
        $script = preg_replace('/(if|elseif|while)\s+([^\(].*?)\s+\{/','\1 (\2) {',$script);
        $this->script = $script;
    }

  public function __set($var,$value) {
    $this->data[$var] = $value;
    
    if ($var == 'script') {
      if ($value !== NULL) {
        $this->split_script();
      }
    }
  }
  
  public function __get($var) {
    return $this->data[$var];
  }

  // Split the script into an array of characters
  private function split_script() {
    $this->script = str_replace("\r",'',$this->script);

    $this->chars = array_slice(preg_split('//',$this->script),1,strlen($this->script));
    array_map(array(&$this,'escape_chars'),&$this->chars);
  }
  
  // Escape HTML characters
  private function escape_chars(&$char) {
    $char = str_replace(array('&','<','>'),array('&amp;','&lt;','&gt;'),$char);  
  }
  
  // Apply highlighting to the script
  public function highlight() {
    $open = '\s,!@^&*\050='; // Characters that start a token
    $close = '\s,!@^&*\051'; // Characters that end a token
    
    $script = $this->script;
    
    // Conditional Operators
    $operators = '!?(?:=|==|===|>|<|>=|<=|\/\/|\\\\|&|isin|isincs|iswm|isnum|isletter'.
    '|isalnum|isalpha|islower|isupper|ison|isop|ishop|isvoice|isvo|isreg|ischan|' .
    'isban|isaop|isavoice|isignore|isprotect|isnotify|iswmcs|\|\||&&|\+|\-|\*|%|\^)';
    
    // Patterns to match for different parts of mIRC scripts
    $patterns = array(
      // Comments
      //Block Style
      // Here I've put a d in front of the pattern. This is a lazy thing I did to tell the script to delete the matched portion of text. It's not part of the regular expression.
      'd/\\013?\s*(\/\*.*?\*\/)\s*\\013?/s'
        // The first element of the replacement will go before each callback, and the second element after each callback
        => array('<span class="mirc_comment">','</span>'),
      // Single Line
      'd/^\s*(;.*)$/m'
        => array('<span class="mirc_comment">','</span>'),
      
      // Number
      '/(?<=^|['.$open.'])([+-]?[\d]+?(?:\.[\d]+?)?)(?=$|['.$close.'%])/m'
        => array('<span class="mirc_number">','</span>'),
      
      // Identifier
      '/(?<=^|['.$open.'])(\$[^\s\050\051\[,]+)/m'
        => array('<span class="mirc_identifier">','</span>'),
      // Identifier Property
      '/(?<=\051)(\.[^\s$\051]+)/m'
        => array('<span class="mirc_identifier">','</span>'),
      
      // Variable
      '/(?<=^|['.$open.'])(\%[^'.$close.']+)(?=$|['.$close.'])/m'
        => array('<span class="mirc_variable">','</span>'),
      
      // Operators
      '/(?<=[\s])('.$operators.')(?=[\s])/m'
        => array('<span class="mirc_operator">','</span>'),
      
      // Special Characters
      '/([\[\]\{\}\050\051\|]+)/m'
        => array('<span class="mirc_character">','</span>'),
      
      // Events
      '/(?<=^)\s*(on|ctcp|raw)\s+([^\:]+?):([^\:]+?):/m'
        => array('<span class="mirc_event">','</span>'),
      
      // Commands
      '/(?<=^|[\{\|]\s)\s*([^\$\%\s]+?)(?=\s|$)/m'
        => array('<span class="mirc_command">','</span>'),
      // Command Switches
      '/(?<=^|[\{\|]\s)\s*(?:[^\$\%\s]+?)\s+(-[^\s]+)(?=\s|$)/m'
        => array('<span class="mirc_command_switch">','</span>'),
    );
    
    $patterns_keys = array_keys($patterns);
    foreach ($patterns_keys as $rpattern) {
      // Iterate through each pattern
      if ($rpattern{0} == 'd') {
        // The 'd' switch means delete the text after matching
        $delete = TRUE;
        $pattern = substr($rpattern,1);
      } else {
        $delete = FALSE;
        $pattern = $rpattern;
      }
      if (preg_match_all($pattern,$script,$matches,PREG_OFFSET_CAPTURE)) {
        // Get all matches for this pattern
        array_shift($matches); // Shift off the part we don't want
        foreach ($matches as $matches2) {
          // Iterate through each callback
          foreach ($matches2 as $match) {
            // Iterate through each match of each callback
            list($text,$offset) = $match;
            // Put the first element before the first character of the callback
            $this->chars[$offset] = $patterns[$rpattern][0] . $this->chars[$offset] ;
            // Put the second element after the last character of the callback
            $this->chars[$offset -1 + strlen($text)] = $this->chars[$offset-1 + strlen($text)] .
              $patterns[$rpattern][1];
            if ($delete) {
              // Delete the entire matched text so we don't match it again
              $script = substr($script,0,$offset) . str_repeat(' ',strlen($text)) .
              substr($script,$offset + strlen($text));
            }
          } // End iterate through each match of callback
        } // End iterate through each callback
      } // End if
    } // End iterate through each pattern
    return $line;
  }
  
  // Returns the script after processing
  // Specify TRUE for $indent to have the script indented
  public function get_script($indent = FALSE) {
    // Implode the array of characters into the finished script
    $output = implode('',$this->chars);
    if ($indent) {
      $lines = explode("\n",$this->script);
      $output = explode("\n",$output);
      $level = 0;
      foreach ($lines as $key => &$line) {
          if ($in_comment) {
              // Don't indent parts of the script that are commented out
              if (preg_match('/^\s*\*\//',$line)) { $in_comment = FALSE; }
              continue;
          }
          // Check for beginning of a comment
          if (preg_match('/^\s*\/\*/',$line)) { $in_comment = TRUE; continue; }
          if (preg_match('/^\s*;/',$line)) { continue; }
          
          // Remove spaces at the beginning of the line
          $output[$key] = preg_replace('/^\s*/','',$output[$key]);
          
          // Decrease indentation if there's a }
          $decrease = preg_match_all('/(?<=\s|^)}(?=\s|$)/',$line);
          // Increase indentation if there's a {
          $increase = preg_match_all('/(?<=\s|^|:){(?=\s|$)/',$line);
          // Increase indentation if there's a $&
          $increase = preg_match_all('/\$\&\s*$/',$line);      
              
          $difference = $increase - $decrease;
          
          if ($difference < 0) { $level += $difference; $difference = 0; }
          if ($level < 0) $level = 0;
          
          $output[$key] = str_repeat(' ',$level * 2) . $output[$key];
          
          $level += $difference;
          $difference = 0;
      }
      $output = implode("\n",$output);
    }
    return $output;
  }
}

?>