Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-7 of 7 total  RSS 

Matching quoted strings in Ruby

An exercise in string processing and regexp matching, inspired by Parsing Quoted Strings in Ruby and Stupid Ruby Quoting Tricks.

#!/usr/local/bin/ruby -w

# some input examples
str = 'foo "bar baz" qux'
str = 'foo "bar baz " "bar baz" " bar baz" "bar "klr mre" " " \' "abc" \' baz " qux'
str = '" \' \'    " \n "   " \' \' "" foo \'ttt sss\' "bar "qqq zzz" baz" "added term" qux  " \' \'    "  yyy xxx'
str = '"""frickin \'#{bar}\'"""'
str = '""    "frickin chicken "    #{bar}""""'
str = '"""frickin "#{bar}""""'
str = '"a "b c" "d "e" f g" """h""""'       # cf. http://snippets.dzone.com/posts/show/4852

# escaped quotes
str = '\"'
str = "\\\""
str = '\\\''
str = "\\'"

# special cases
str = '"G","H I"'
str = '"G","H I""G","H I"'

str = '"abc""def"'
str = '"""a""b"'
str = '"abc""def""abc""def""abc""def"'
str = '"a"\'\'"b"'

str = "abc,def,\"efg,hij\",klm,nop,\"qrstuv\",wxyz";


puts
puts "input string:  #{str}" 
puts "str.inspect :  #{str.inspect}" 
puts

num_of_chars1 = str.count('a-zA-Z_0-9', "^\000ds")

error_code = 0      # in case of a parsing error Shellwords will be used instead of regex1 & regex2
str2 = str.clone

# encode escaped quotes
str = str.gsub(/\\"|\\'/) { |m| m =~ /^\\"$/ ? "\000d\000" : "\000s\000" }

dq_count = str.count('"')
sq_count = str.count("'")

if dq_count % 2 != 0 && sq_count % 2 != 0
   raise ArgumentError, "\e[1modd number of single & double quotes\e[m in: #{str}\nsq_count: #{sq_count}\ndq_count: #{dq_count}\n"
elsif dq_count % 2 != 0
   raise ArgumentError, "\e[1modd number of double quotes\e[m in: #{str}\ndq_count: #{dq_count}\n"
elsif sq_count % 2 != 0
   raise ArgumentError, "\e[1modd number of single quotes\e[m in: #{str}\nsq_count: #{sq_count}\n"
end

# regex1 separates substrings that contain quotes from substrings that do not contain quotes
regex1 = %r{[^"']+|["'].*?["'](?!.*["'])}m  

# example
#"abc 'quote1' pjk 'quote2' xyz".scan(regex1) { |m| puts m } 


regex2 = %r{
\s*["'][^"']+["'][[:punct:]]["'][^"']+["']|  # special case:  xxx "ab c","def g" yyy
\s*["'][^"']+["']{2,}[^"']+["']|             # special case:  xxx "abc""def" yyy
\s*["']\S+["']|

\s'\s|                       # xxx ' yyy
\s"\s|                       # xxx " yyy
\s''\s|                      # xxx '' yyy
\s""\s|                      # xxx "" yyy
\s'\s+'\s|                   # xxx '   ' yyy
\s"\s+"\s|                   # xxx "   " yyy
\s"\s[^"]+\s"\s|             # xxx " abc " yyy
\s'\s[^']+\s'\s|             # xxx ' abc ' yyy
\s["']["']+(?=[^"'\s])|      # :qoblock:  xxx "'""'abc yyy
[^"'\s]["']["']+(?=\s)|      # :qcblock:  xxx abc"'""' yyy
\s""+|                       # :dqoblock:  xxx """abc yyy
\s''+|                       # :sqoblock:  xxx '''abc yyy
[^"]""+|                     # :dqcblock:  xxx abc"" yyy
[^']''+|                     # :sqcblock:  xxx abc'' yyy
\s["'](?=[^"'\s])|           # :dqo or :sqo:  xxx "abc yyy  or  xxx 'abc yyy
[^"'\s]["'](?=\s)|           # :dqc or :sqc:  xxx abc" yyy  or  xxx abc' yyy
[^"']+[^"'\s](?=\s)          # no quotes at all
}mx


=begin

There are different kinds of quotes matched by regex2 below. They include:

- :sqo (single quote open)
- :sqc (single quote close)
- :sqoblock (single quote open block)
- :sqcblock (single quote close block)

- :dqo (double quote open)
- :dqc (double quote close)
- :dqoblock (double quote open block)
- :dqcblock (double quote close block)

- :qoblock (quote open block)
- :qcblock (quote close block)

=end


ret = []

str.scan(regex1) do |s| 

   if s !~ /\A["']/

      #puts "s1: #{s}"
      #puts "s1.inspect: #{s.inspect}"

      s.split(/\s+/m).each { |t| ret << t unless t.empty? }

   else

      #puts "s2: #{s}"
      #puts "s2.inspect: #{s.inspect}"

      open_quotes = 0
      close_quotes = 0
      ar = []

      # add spaces to simplify regex2 matching
      s = "\x20" << s << "\x20"    
      s.gsub!(/\x20/, "\x20\x20")  


      s.scan(regex2) do |m|

         # get the index of the quote
         # + 1 for leading space or non-space
         # $` is the prematch string

         index = $`.length + 1 

         post_match = $'  

         #puts
         #puts "index: #{index}"
         #puts "m: #{m.inspect}"
         #puts "m.length: #{m.length}"
         #puts "open_quotes:  #{open_quotes}\nclose_quotes: #{close_quotes}"
         #puts "ret: #{ret.inspect}"
         #puts "ar: #{ar.inspect}"
         #puts


         if m =~ /\A\s''\s\z/

            next unless open_quotes == 0 && close_quotes == 0
            ret << ''
            next

         elsif m =~ /\A\s""\s\z/

            next unless open_quotes == 0 && close_quotes == 0
            ret << ""
            next

         # example: xxx "ab c","def g" yyy
         elsif open_quotes.zero? && close_quotes.zero? && m =~ /\A\s*["'][^"']+["'][[:punct:]]["'][^"']+["']\z/ && m.count('"') % 2 == 0 && m.count("'") % 2 == 0           

            m = m.gsub(/\x20\x20/, "\x20")
            # cf. http://henrik.nyh.se/2008/03/flickr-style-tag-splitting-in-ruby
            m = m.split(/"(.+?)"|\s+/).reject {|s| s.empty? }
            #m = m.split(/"(.+?)"|'(.+?)'|\s+/).reject {|s| s.empty? }
            #m = m.split(/"(.+?)"|'(.+?)'|([[:punct:]])|\s+/).reject {|s| s.empty? }
            ret.concat(m)
            next

         # example: xxx "abc""def" yyy
         elsif open_quotes.zero? && close_quotes.zero? && m =~ /\A\s*["'][^"']+["']{2,}[^"']+["']\z/ && m.count('"') % 2 == 0 && m.count("'") % 2 == 0           
            
            m = m.gsub(/\x20\x20/, "\x20")
            m = m.split(/"(.+?)"|\s+/).reject {|s| s.empty? }
            #m = m.split(/"(.+?)"|'(.+?)'|\s+/).reject {|s| s.empty? }
            ret.concat(m)
            next

         elsif open_quotes.zero? && close_quotes.zero? && m =~ /\A\s*["']\S+["']\z/ && m.count('"') % 2 == 0 && m.count("'") % 2 == 0

            ret.concat(m.split(/"(.+?)"|\s+/).reject {|s| s.empty? })
            next

         elsif m =~ /\A\s"\s[^"]+\s"\s\z/

            next unless open_quotes == 0 && close_quotes == 0
            ret << m.gsub(/\x20\x20/, "\x20").strip[1..-2]
            next

         elsif m =~ /\A\s'\s[^']+\s"\s\z/

            next unless open_quotes == 0 && close_quotes == 0
            ret << m.gsub(/\x20\x20/, "\x20").strip[1..-2]
            next

         elsif m =~ /\A\s'\s+'\s\z/

            next unless open_quotes == 0 && close_quotes == 0
            ret << m.gsub(/\x20\x20/, "\x20").strip[1..-2]
            next

         elsif m =~ /\A\s"\s+"\s\z/

           next unless open_quotes == 0 && close_quotes == 0
           ret << m.gsub(/\x20\x20/, "\x20").strip[1..-2]
           next


         elsif m =~ /\A\s""+\z/

            l = m.strip.length
            ar << [:dqoblock, index, l]
            old_open_quotes = open_quotes
            open_quotes += l

            if close_quotes == 0 && old_open_quotes == 0 && open_quotes % 2 == 0 && post_match !~ /"/
               ret << m[2..-2] 
               open_quotes = 0
               ar.pop
               next
            end


         elsif m =~ /\A\s''+\z/

            l = m.strip.length
            ar << [:sqoblock, index, l]
            old_open_quotes = open_quotes
            open_quotes += l

            if close_quotes == 0 && old_open_quotes == 0 && open_quotes % 2 == 0 && post_match !~ /'/
               ret << m[2..-2] 
               open_quotes = 0
               ar.pop
               next
            end


         elsif m =~ /\A[^"]""+\z/

            l = m[1..-1].strip.length
            ar << [:dqcblock, index+l-1, l]      #  index+l-1 is the index of the last closing quote: ''"'[']
            old_close_quotes = close_quotes
            close_quotes += l

            if open_quotes == 0 && old_close_quotes == 0 && close_quotes % 2 == 0 && post_match !~ /"/
               ret << m[2..-2] 
               close_quotes = 0
               ar.pop
               next
            end

         elsif m =~ /\A[^']''+\z/

            l = m[1..-1].strip.length
            ar << [:sqcblock, index+l-1, l]
            old_close_quotes = close_quotes
            close_quotes += l

            if open_quotes == 0 && old_close_quotes == 0 && close_quotes % 2 == 0 && post_match !~ /'/
               ret << m[2..-2] 
               close_quotes = 0
               ar.pop
               next
            end


         elsif m =~ /\A\s'\z/

            ar << [:sqo, index, 1]
            open_quotes += 1

         elsif m =~ /\A\S'\z/

            ar << [:sqc, index, 1]
            close_quotes += 1

         elsif m =~ /\A\s"\z/

            ar << [:dqo, index, 1]
            open_quotes += 1

         elsif m =~ /\A\S"\z/

            ar << [:dqc, index, 1]
            close_quotes += 1


         else


            if m =~ /\A\s"\s\z/              # " surrounded by whitespace

               if open_quotes > close_quotes

                  ar << [:dqc, index, 1]
                  close_quotes += 1

                  # avoid :sqo followed by :dqc or :sqc followed by :dqc
                  if post_match =~ /"/ && open_quotes == close_quotes && (ar.at(-2).first == :sqo || ar.at(-2).first == :sqc)
                     ar.pop
                     ar << [:dqo, index, 1]
                     close_quotes -= 1
                     open_quotes += 1
                  end

               else 

                  ar << [:dqo, index, 1]
                  open_quotes += 1

               end


            elsif m =~ /\A\s'\s\z/          # ' surrounded by whitespace

               if open_quotes > close_quotes

                  ar << [:sqc, index, 1]
                  close_quotes += 1

                  # avoid :dqo followed by :sqc or :dqc followed by :sqc
                  if post_match =~ /'/ && open_quotes == close_quotes && (ar.at(-2).first == :dqo || ar.at(-2).first == :dqc)
                     ar.pop
                     ar << [:sqo, index, 1]
                     close_quotes -= 1
                     open_quotes += 1
                  end

               else 

                  ar << [:sqo, index, 1]
                  open_quotes += 1

               end


            elsif m =~ /\A\s["']["']+\z/              # :qoblock: xxx "'""'abc yyy

               l = m[1..-1].strip.length
               ar << [:qoblock, index, l]
               old_open_quotes = open_quotes
               open_quotes += l

               if close_quotes == 0 && old_open_quotes == 0 && open_quotes % 2 == 0 && post_match !~ /["']/
                  ret << m[2..-2] 
                  open_quotes = 0
                  ar.pop
                  next
               end


            elsif m =~ /\A[^"'\s]["']["']+\z/          # :qcblock: xxx abc"'""' yyy

               l = m[1..-1].strip.length
               ar << [:qcblock, index+l-1, l]
               old_close_quotes = close_quotes
               close_quotes += l

               if open_quotes == 0 && old_close_quotes == 0 && close_quotes % 2 == 0 && post_match !~ /["']/
                  ret << m[2..-2] 
                  close_quotes = 0
                  ar.pop
                  next
               end


            elsif m =~ /\A[^"']+[^"'\s]\z/          # part of quoted substring contains neither " nor '
               next unless open_quotes == 0 && close_quotes == 0
               next if m.strip.empty?
               ret << m.gsub(/\x20\x20/, "\x20").strip; next
            end

         end

         puts
         puts "open_quotes:  #{open_quotes}\nclose_quotes: #{close_quotes}\n"
         #puts "ar: #{ar.inspect}"

         if open_quotes == close_quotes

            #puts "open_quotes & close_quotes: #{close_quotes}"
            puts "ar: #{ar.inspect}"

            ret << s[ar.first[1]..ar.last[1]].gsub(/\x20\x20/, "\x20")[1..-2] unless ar.empty?

            ar.clear
            open_quotes = 0
            close_quotes = 0

         end

      end   # scan 2

      unless open_quotes.zero? && close_quotes.zero?
        error_code = 1
        puts "\e[1mparsing error\e[m for the quoted string: #{str.strip.squeeze[0..20]}"
        #raise "\e[1mparsing error\e[m for the quoted string: #{str.strip.squeeze[0..20]}"
      end

   end   # if

end   # scan 1



num_of_chars2 = ret.join.count('a-zA-Z_0-9', "^\000ds")

unless num_of_chars1 == num_of_chars2
   error_code = 1
   puts "\n\e[1mparsing error due to wrong number of characters a-zA-Z_0-9\e[m: \n#{num_of_chars2} instead of #{num_of_chars1}\n"
   #raise "\e[1mparsing error due to wrong number of characters a-zA-Z_0-9\e[m: \n#{num_of_chars2} instead of #{num_of_chars1}\n in #{str.strip.squeeze[0..20]}"
end


# use Shellwords in case the quote matching above failed
if error_code == 1       
#if error_code == 1 || ret.join =~ /\A["']+\z/        
   require 'shellwords'
   ret.clear
   ret.concat(Shellwords::shellwords(str))
   #str =~ /\A\S+\z/ ? ret.concat(str.split(/"(.+?)"|\s+/).reject {|s| s.empty? }) : ret.concat(Shellwords::shellwords(str))
end 



puts "\n\e[1mResult\e[m:\n\n"
ret.each_with_index do |t,i| 
   # decode encoded escaped quotes 
   t = t.gsub(/\000d\000|\000s\000/) { |m| m =~ /^\000d\000$/ ? '\"' : "\\'" }
   puts "#{i+1}:  #{t.inspect}" 
end

puts "\n\e[1mShellwords\e[m:\n\n"
require 'shellwords'
Shellwords::shellwords(str2).each_with_index { |t,i| puts "#{i+1}:  #{t.inspect}" }


#----------------------


# matching quoted strings using backreferences
# See: Regexes in Depth: Advanced Quoted String Matching,
# http://blog.stevenlevithan.com/archives/match-quoted-string

str = '"abc"'

regex = %r{(["'])([^"']*)(\1)}
regex = %r{(["'])([^\1]*)(\1)}
p regex

str.scan(regex) { |m| p m; p $1 << $2 << $3 }

Finding your match with Ruby

This example finds an email subject in a string and passes the value to a variable called 'subject'.
subject = (/^Subject\: (.+)$/).match(email)[1]

Prior to this code I would have used the following:
  email[/^Subject\: (.+)$/]
  subject = $1

Reference: Ruby SMTP Server - Save to Database [dzone.com]

bScan - Simple Web Aplications Scanner

// Web application scanner (ex: phpBB, myCMS, myBlog, mySite etc..) - Only in PHP !
// Find XSS, sql injection, remote file inclusion

#####################################################################################
#	Black_H  / Nooz -- 30:01:07 
#	Bl4ck.H<>gmail<>com
#

class BScan

#####################################################################################
#	Regex
#

@@space    = '([[:space:]]*)'

@@userdat  = '('
@@userdat += '(\$_SERVER\[([\'\"]*)HTTP_)|'
@@userdat += '(\$_GET)|'
@@userdat += '(\$_POST)|'
@@userdat += '(\$_COOKIE)|'
@@userdat += '(\$_REQUEST)|'
@@userdat += '(\$_FILES)|'
@@userdat += '(\$_ENV)|'
@@userdat += '(\$_HTTP_COOKIE_VARS)|'
@@userdat += '(\$_HTTP_ENV_VARS)|'
@@userdat += '(\$_HTTP_GET_VARS)|'
@@userdat += '(\$_HTTP_POST_FILES)|'
@@userdat += '(\$_HTTP_POST_VARS)|'
@@userdat += '(\$_HTTP_SERVER_VARS\[([\'\"]*)HTTP_)'
@@userdat += ')'

@@regex = Hash.new
@@regex = 
	{'TYPE' => 'vars overwrite','LEVEL' => '2','REGEX' => /extract#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'vars overwrite','LEVEL' => '2','REGEX' => /import_request_variables#{@@space}\((.*)\)/i},
	{'TYPE' => 'fopen vuln','LEVEL' => '3','REGEX' => /fopen#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'copy vuln','LEVEL' => '3','REGEX' => /copy#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'fwrite vuln','LEVEL' => '3','REGEX' => /fwrite#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'sql injection','LEVEL' => '2','REGEX' => /(mysql_query|mssql_query|mysqli_query)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'crlf injection','LEVEL' => '1','REGEX' => /mail#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'cross site scripting','LEVEL' => '1','REGEX' => /\<\?\=#{@@space}(.*)#{@@userdat}/i},
	{'TYPE' => 'cross site scripting','LEVEL' => '1','REGEX' => /(print|echo|print_r|var_dump)#{@@space}(|\(|\")(.*)#{@@userdat}/i},
	{'TYPE' => 'php code execution','LEVEL' => '3','REGEX' => /eval#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'php code execution','LEVEL' => '3','REGEX' => /file_put_contents#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'variable attribution', 'LEVEL' => '2','REGEX' => /(.*)\$#{@@userdat}(.*)/i},
	{'TYPE' => 'chmod affectation','LEVEL' => '1','REGEX' => /chmod#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file disclosure','LEVEL' => '2','REGEX' => /(readfile|file_get_contents|file)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file disclosure','LEVEL' => '2','REGEX' => /(show_source|highlight_file)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'bzopen vuln','LEVEL' => '2','REGEX' => /bzopen#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file deletion','LEVEL' => '2','REGEX' => /(rmdir|unlink|delete)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'command execution','LEVEL' => '3','REGEX' => /(exec|system|passthru|shell_exec|proc_open|pcntl_exec)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'buffer overflow','LEVEL' => '3','REGEX' => /(confirm_phpdoc_compiled|mssql_pconnect|mssql_connect|crack_opendict|snmpget|ibase_connect)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'ip falsification','LEVEL' => '1','REGEX' => /(.*)(HTTP_CLIENT_IP|HTTP_X_FORWARDED_FOR|HTTP_PC_REMOTE_ADDR)(.*)/i},
	{'TYPE' => 'putenv vuln','LEVEL' => '2','REGEX' => /putenv#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'full path disclosure','LEVEL' => '1','REGEX' => /(htmlentities|htmlspecialchars)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'magic_quotes_gpc bypass','LEVEL' => '1','REGEX' => /(stripslashes|urldecode)#{@@space}\((.*)#{@@userdat}(.*)\)/i},
	{'TYPE' => 'file inclusion','LEVEL' => '3','REGEX' => /(include|include_once|require|require_once)#{@@space}(|\(|\")(.*)#{@@userdat}/i}

#####################################################################################
#	Main
#

  def initialize()

	################
	#	Usage

if (ARGV.length < 4)
puts  '
 ---------------------------------------------------------------------
|             Credits: Black_H <bl4ck.h@gmail.com>                    |
|                 URL: Lemon-Inside.sup.fr                            |
|                Note: Premier code Ruby                              |
 ---------------------------------------------------------------------

 ---------------------------------------------------------------------
|   Usage:  scan.rb -d <Dossier> -i <Save.html>                       |
|   Ex:  scan.rb -d ./ -i output.html                                 |
 ---------------------------------------------------------------------		
 '
 end
 
	################
	#	Options & Vars
	
	@@scan_alldir =  self.options('d')
	@@out_file =  self.options('i')
	
	@@ban = [".", "..", "scan.rb", @@out_file.to_s]

	@@scan_buffer = Array.new
	
	################
	#	Options Error ?
	
	if (@@scan_alldir != false and @@scan_alldir.empty? == false)
	self.dscan(@@scan_alldir)
	self.output(@@scan_buffer)
	@@scan_buffer = ''
	end


	

  end

#####################################################################################
#	Dir Scan 
#
  
  def dscan(dir)
      
	d = Dir.open(dir.to_s)
	d = d.sort - @@ban
	
      d.each { |fichier|

      case File.ftype(dir+fichier)
        when "directory"
          self.dscan(dir + fichier + "/")
        when "file"
		  puts  'Scan => ' + dir + fichier 
          self.fscan(dir + fichier)
      end

	  }
  end

#####################################################################################
#	File Scan 
#
  
  def fscan(file)

	fichier = File.readlines(file)
	i = 1

	fichier.each { |line|
						
		@@regex.each  { |info|
			
			test = (line  =~ info['REGEX']) 
		
				if (test) 
			
				@@scan_buffer += ['FILE' => file, 'LINE' => i.to_s, 'MATCH' => line, 'LEVEL' => info['LEVEL'], 'TYPE' => info['TYPE']]
				#	5 , 1 , 3 , 4 , 2
				next @@scan_buffer
				end
		}

	i += 1
  	} 
	
  end

#####################################################################################
#	Output buffer
#
  
  def output(buffer)
  
	@html_hmodel = '<html>'
	@html_hmodel += '<style type="text/css">'
	@html_hmodel += '<!--'
	@html_hmodel += '.level0 {background-color: #CCCCCC;}'
	@html_hmodel += '.level1 {background-color: #33FF66;}'
	@html_hmodel += '.level2 {background-color: #FFFF33;}'
	@html_hmodel += '.level3 {background-color: #FF0000;}'
	@html_hmodel += '--></style><body><h1>BScan v1.0</h1><pre>'

	code = @html_hmodel
	
	buffer.each { |infos|
	
	keys = infos.keys
	code += "<span class='level" + infos["LEVEL"] + "'>" + keys[1].to_s + ' : ' + infos["TYPE"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[3].to_s + ' : ' + infos["LEVEL"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[4].to_s + ' : ' + infos["FILE"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[0].to_s + ' : ' + infos["LINE"] + '</span><br />'
	code += "<span class='" + infos["LEVEL"] + "'>" + keys[2].to_s + ' : ' + infos["MATCH"] + '</span><br />'
	

	}
		code += "</pre></body></html>"
		fhtml = File.open(@@out_file.to_s, "w")
		fhtml.write code
		code = ''

	
  end
#####################################################################################
#	Parse & Get Options
#
 
  def options(param)
  
	i = 0
		ARGV.each  { |valeur|
		
    		if (valeur == '-' + param.to_s)
				return ARGV[i+1]
			elseif (valeur != '-' + param.to_s)
				return false
			end
		i += 1
		}
		
	end
  
end

scan = BScan.new

Automate the insertion of text into a file.

This example updates an xsl file with a new xsl:include declaration, and with a javascript header declaration. It reads 'guide.xsl' as a text file, and reads the template 'guide_ptemplate.xml' as a rexml document.

#!/usr/bin/ruby
#file: create add2guide_xsl.rb

require 'rexml/document'
include REXML

class Add2GuideTxt
  def initialize
    @guide = 'guide.xsl'
    @guide_template = 'guide_ptemplate.xml'
  end
  
  def insertText(project)
    # read guide.txt and return the buffer
    buffer = readGuide(@guide)    
    replaceBuffer(project, buffer, @guide) if not buffer.match("<xsl:include href='/xsl/#{project}.xsl'/>")
  end
  
  def replaceBuffer(project, buffer, output_file)
    # read guide_ptemplate.xsl and return the doc
    doc = readGuideTemplate(@guide_template)    
    # read the xsl:include
    xsl_include = buildIncludeTemplate(project, doc)
    # read the xsl:if
    xsl_if = buildIfTemplate(project,doc)
    
    eoi = "<!-- </xsl_includes> -->"
    buffer = buffer.gsub(eoi, "#{xsl_include}\n" + eoi)
    eoj = "<!--</xsl_javascript> -->"
    buffer = buffer.gsub(eoj, "\n#{xsl_if}\n" + eoj)
    
    file = File.new(output_file,'w')
    file.puts buffer.gsub("&quot;","'")
    file.close
  end
  
  def buildIncludeTemplate(project, doc)
    xsl_include = doc.root.elements['xsl:include']
    xsl_include