devdaily home | apple | java | perl | unix | directory | blog

What this is

This file is included in the DevDaily.com "Ruby Source Code Warehouse" project. The intent of this project is to help you "Learn Ruby by Example" TM.

Other links

The source code

#
# Win32::Console::ANSI
#
# Copyright 2004 - Gonzalo Garramuno
# Licensed under GNU General Public License or Perl's Artistic License
#
# Based on Perl's Win32::Console::ANSI
# Copyright (c) 2003 Jean-Louis Morel 
# Licensed under GNU General Public License or Perl's Artistic License
#
require "win32/Console"

module Win32
  class Console
    module ANSI

      class IO < IO

	VERSION = '0.05'
	DEBUG = nil

	require "win32/registry"

	include Win32::Console::Constants

	# @todo: encode is another perl module
	EncodeOk = false

	# Retrieving the codepages
	cpANSI = nil
	Win32::Registry::HKEY_LOCAL_MACHINE.open('SYSTEM\CurrentControlSet\Control\Nls\CodePage' ) { |reg|
	  cpANSI = reg['ACP']
	}

	STDERR.puts "Unable to read Win codepage #{cpANSI}" if DEBUG && !cpANSI


	cpANSI = 'cp'+(cpANSI ? cpANSI : '1252')      # Windows codepage
	OEM = Win32::Console::OutputCP()
	cpOEM = 'cp' + OEM.to_s                       # DOS codepage
	@@cp = cpANSI + cpOEM

	STDERR.puts "EncodeOk=#{EncodeOk} cpANSI=#{cpANSI} "+
	  "cpOEM=#{cpOEM}" if DEBUG

	@@color = { 30 => 0,                                               # black foreground
              31 => FOREGROUND_RED,                                  # red foreground
              32 => FOREGROUND_GREEN,                                # green foreground
              33 => FOREGROUND_RED|FOREGROUND_GREEN,                 # yellow foreground
              34 => FOREGROUND_BLUE,                                 # blue foreground
              35 => FOREGROUND_BLUE|FOREGROUND_RED,                  # magenta foreground
              36 => FOREGROUND_BLUE|FOREGROUND_GREEN,                # cyan foreground
              37 => FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE, # white foreground
              40 => 0,                                               # black background
              41 => BACKGROUND_RED,                                  # red background
              42 => BACKGROUND_GREEN,                                # green background
              43 => BACKGROUND_RED|BACKGROUND_GREEN,                 # yellow background
              44 => BACKGROUND_BLUE,                                 # blue background
              45 => BACKGROUND_BLUE|BACKGROUND_RED,                  # magenta background
              46 => BACKGROUND_BLUE|BACKGROUND_GREEN,                # cyan background
              47 => BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE, # white background
	}

	def initialize
	  super(1,'w')
	  @Out = Win32::Console.new(STD_OUTPUT_HANDLE)
	  @x = @y = 0           # to save cursor position
	  @foreground = 7
	  @background = 0
	  @bold = 
	  @underline = 
	  @revideo = 
	  @concealed = nil
	  @conv = 1        # char conversion by default
	end


	def write(*s)
	  s.each { |x|
	    _PrintString(x)
	  }
	end


	private

	def _PrintString(t)
	  s = t.dup
	  while s != ''
	    if s.sub!( /([^\e]*)?\e([\[\(])([0-9\;\=]*)([a-zA-Z@])(.*)/s,'\5')
	      @Out.Write((_conv("#$1")))
	      if $2 == '['
		case $4
		when 'm'        # ESC[#;#;....;#m Set display attributes
		  attributs = $3.split(';')
		  attributs.push(nil) unless attributs  # ESC[m == ESC[;m ==...==ESC[0m
		  for attr in attributs
		    atv = attr.to_i
		    if atv > 0
		      if atv == 1
			@bold = 1
		      elsif atv == 21
			@bold = nil
		      elsif atv == 4
			@underline = 1
		      elsif atv == 24
			@underline = nil
		      elsif atv == 7
			@revideo = 1
		      elsif atv == 27
			@revideo = nil
		      elsif atv == 8
			@concealed = 1
		      elsif atv == 28
			@concealed = nil
		      elsif atv >= 30 and atv <= 37
			@foreground = atv - 30
		      elsif atv >=40 and atv <=47
			@background = atv - 40
		      end
		    else                              # ESC[0m reset
		      @foreground = 7
		      @background = 0
		      @bold = 
		      @underline = 
		      @revideo = 
		      @concealed = nil
		    end
		  end

		  if @revideo
		    attribut = @@color[40+@foreground] | 
		      @@color[30+@background]
		  else
		    attribut = @@color[30+@foreground] | 
		      @@color[40+@background]
		  end
		  attribut |= FOREGROUND_INTENSITY if @bold
		  attribut |= BACKGROUND_INTENSITY if @underline
		  @Out.Attr(attribut)
		when 'J'
		  if !$3 or $3 == ''  # ESC[0J from cursor to end of display
		    info = @Out.Info()
		    s = ' ' * ((info[1]-info[3]-1)*info[0]+info[0]-info[2]-1)
		    @Out.WriteChar(s, info[2], info[3])
		    @Out.Cursor(info[2], info[3])
		  elsif $3 == '1' # ESC[1J erase from start to cursor.
		    info = @Out.Info()
		    s = ' ' * (info[3]*info[0]+info[2]+1)
		    @Out.WriteChar(s, 0, 0)
		    @Out.Cursor(info[2], info[3])
		  elsif $3 == '2' # ESC[2J Clear screen and home cursor
		    @Out.Cls()
		    @Out.Cursor(0, 0)
		  else
		    STDERR.print "\e#$2#$3#$4" if DEBUG # if ESC-code not implemented
		  end
		when 'K'
		  info = @Out.Info()
		  if !$3 or $3 == ''                  # ESC[0K Clear to end of line
		    s = ' ' * (info[7]-info[2]+1)
		    @Out.Write(s)
		    @Out.Cursor(info[2], info[3])
		  elsif $3=='1'   # ESC[1K Clear from start of line to cursor
		    s = ' '*(info[2]+1)
		    @Out.WriteChar(s, 0, info[3])
		    @Out.Cursor(info[2], info[3])
		  elsif $3=='2'   # ESC[2K Clear whole line.
		    s = ' '* info[0]
		    @Out.WriteChar(s, 0, info[3])
		    @Out.Cursor(info[2], info[3])
		  end
		when 'L'  # ESC[#L Insert # blank lines.
		  n = $3 == ''? 1 : $3.to_i  # ESC[L == ESC[1L
		  info = @Out.Info()
		  @Out.Scroll(0, info[3], info[0]-1, info[1]-1,
			      0, info[3] + n.to_i,
                               ' '[0], @Out.Attr(),
                               0, 0, 10000, 10000)
		  @Out.Cursor(info[2], info[3])
		when 'M'   # ESC[#M Delete # line.
		  n = $3 == ''? 1 : $3.to_i  # ESC[M == ESC[1M
		  info = @Out.Info();
		  @Out.Scroll(0, info[3]+n, info[0]-1, info[1]-1,
			      0, info[3],
			      ' '[0], @Out.Attr(),
			      0, 0, 10000, 10000)
		  @Out.Cursor(info[2], info[3])
		when 'P'   # ESC[#P Delete # characters.
		  n = $3 == ''? 1 : $3.to_i  # ESC[P == ESC[1P
		  info = @Out.Info()
		  n = info[0]-info[2] if info[2]+n > info[0]-1
		  @Out.Scroll(info[2]+n, info[3] , info[0]-1, info[3],
			      info[2], info[3],
			      ' '[0], @Out.Attr(),
			      0, 0, 10000, 10000)
		  s = ' ' * n
		  @Out.Cursor(info[0]-n, info[3])
		  @Out.Write(s)
		  @Out.Cursor(info[2], info[3])
		when '@'      # ESC[#@ Insert # blank Characters
		  s = ' ' * $3.to_i
		  info = @Out.Info()
		  s << @Out.ReadChar(info[7]-info[2]+1, info[2], info[3])
		  s = s[0..-($3.to_i)]
		  @Out.Write(s);
		  @Out.Cursor(info[2], info[3])
		when 'A'     # ESC[#A Moves cursor up # lines
		  (x, y) = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[A == ESC[1A
		  @Out.Cursor(x, y-n)
		when 'B'    # ESC[#B Moves cursor down # lines
		  (x, y) = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[B == ESC[1B
		  @Out.Cursor(x, y+n)
		when 'C'    # ESC[#C Moves cursor forward # spaces
		  (x, y) = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[C == ESC[1C
		  @Out.Cursor(x+n, y)
		when 'D'    # ESC[#D Moves cursor back # spaces
		  (x, y) = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[D == ESC[1D
		  @Out.Cursor(x-n, y)
		when 'E'    # ESC[#E Moves cursor down # lines, column 1.
		  x, y = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[E == ESC[1E
		  @Out.Cursor(0, y+n)
		when 'F'    # ESC[#F Moves cursor up # lines, column 1.
		  x, y = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[F == ESC[1F
		  @Out.Cursor(0, y-n)
		when 'G'   # ESC[#G Moves cursor column # in current row.
		  x, y = @Out.Cursor()
		  n = $3 == ''? 1 : $3.to_i;  # ESC[G == ESC[1G
		  @Out.Cursor(n-1, y)
		when 'f' # ESC[#;#f Moves cursor to line #, column #
		  y, x = $3.split(';')
		  x = 1 unless x    # ESC[;5H == ESC[1;5H ...etc
		  y = 1 unless y
		  @Out.Cursor(x.to_i-1, y.to_i-1) # origin (0,0) in DOS console
		when 'H' # ESC[#;#H  Moves cursor to line #, column #
		  y, x = $3.split(';')
		  x = 1 unless x    # ESC[;5H == ESC[1;5H ...etc
		  y = 1 unless y
		  @Out.Cursor(x.to_i-1, y.to_i-1) # origin (0,0) in DOS console
		when 's'       # ESC[s Saves cursor position for recall later
		  (@x, @y) = @Out.Cursor()
		when 'u'       # ESC[u Return to saved cursor position
		  @Out.Cursor(@x, @y)
		else
		  STDERR.puts "\e#$2#$3#$4 not implemented" if DEBUG  # ESC-code not implemented
		end
	      else
		case $4
		when 'U'     # ESC(U no mapping
		  @conv = nil
		when 'K'     # ESC(K mapping if it exist
		  @Out.OutputCP(OEM)      # restore original codepage
		  @conv = 1
		when 'X'     # ESC(#X codepage **EXPERIMENTAL**
		  @conv = nil
		  @Out.OutputCP($3)
		else
		  STDERR.puts "\e#$2#$3#$4 not implemented" if DEBUG # ESC-code not implemented
		end
	      end
	    else
	      @Out.Write(_conv(s))
	      s=''
	    end
	  end
	end

	def _conv(s)
	  if @concealed
	    s.gsub!( /\S/,' ')
	  elsif @conv
	    if EncodeOk
	      from_to(s, cpANSI, cpOEM)
	    elsif @@cp == 'cp1252cp850'      # WinLatin1 --> DOSLatin1
	      s.tr!("ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁","?????????????????????????????ρ݁󁨁ǎԐҁӁށցׁ؁с噞ꚁᅁƄЁ䔁")
	    elsif @@cp == 'cp1252cp437'      # WinLatin1 --> DOSLatinUS
	      s.tr!("ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁", "???????????????????????????????????????????????????????????????????ᅁ??????")
	    elsif @@cp == 'cp1250cp852'      # WinLatin2 --> DOSLatin2
	      s.tr!("ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁",
              "??????????????????????ρ???????񖁾聵ƎӁցׁҁсՁ⊙ށ뚁݁ꁠDŽ؁ԁЁ偢" )
	    elsif @@cp == 'cp1251cp855'      # WinCyrillic --> DOSCyrillic
	      s.tr!("ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁",
              "?????????????????????????????쁭􁸁ǁсӁՁׁ݁聫끬󁷁ƁЁҁԁց؁灪")
	    end
	  end
	  return s
	end

      end

# end print overloading

    end
  end
end


$stdout = Win32::Console::ANSI::IO.new()




Copyright 1998-2008 Alvin Alexander
All Rights Reserved.
 
devdaily.com is based in louisville, kentucky, and this web site is hosted by godaddy.com