[BACK]Return to ox-c.rb CVS log [TXT][DIR] Up to [local] / OpenXM / src / ruby

File: [local] / OpenXM / src / ruby / ox-c.rb (download)

Revision 1.1, Sat Sep 9 00:34:58 2000 UTC (23 years, 8 months ago) by takayama
Branch: MAIN
CVS Tags: maekawa-ipv6, R_1_3_1-2, RELEASE_1_3_1_13b, RELEASE_1_2_3_12, RELEASE_1_2_3, RELEASE_1_2_2_KNOPPIX_b, RELEASE_1_2_2_KNOPPIX, RELEASE_1_2_2, RELEASE_1_2_1, RELEASE_1_1_3, KNOPPIX_2006, HEAD, DEB_REL_1_2_3-9

A sample ruby client to call OpenXM servers.

# ox-c.rb OpenXM client written by Ruby  
#   (takayama's version based on ogino's ox.rb)
#
# $OpenXM: OpenXM/src/ruby/ox-c.rb,v 1.1 2000/09/09 00:34:58 takayama Exp $
# 
require 'socket'
include Socket::Constants

# define for CMO constants

# Moved from oxtag.h
LARGEID =   0x7f000000
CMO_PRIVATE = 0x7fff0000
CMO_ERROR =  (LARGEID+1)
CMO_ERROR2 = (LARGEID+2)
CMO_NULL =   1
CMO_INT32 =  2
CMO_DATUM =  3
CMO_STRING = 4
CMO_MATHCAP = 5

CMO_START_SIGNATURE = 0x7fabcd03     
CMO_LOCAL_OBJECT    = 0x7fcdef03
CMO_LOCAL_OBJECT_ASIR = (CMO_LOCAL_OBJECT+0)
CMO_LOCAL_OBJECT_SM1  = (CMO_LOCAL_OBJECT+1)
# for OpenMathematica 
MLO_FUNCTION          = (CMO_LOCAL_OBJECT+2)

OX_LOCAL_OBJECT =       0x7fcdef30
OX_LOCAL_OBJECT_ASIR =   (OX_LOCAL_OBJECT+0)
OX_LOCAL_OBJECT_SM1  =   (OX_LOCAL_OBJECT+1)
OX_LOCAL_OBJECT_MATH =   (OX_LOCAL_OBJECT+2)

CMO_ARRAY = 16
CMO_LIST = 17
CMO_ATOM = 18
CMO_MONOMIAL32 = 19
CMO_ZZ =         20
CMO_QQ =         21
CMO_ZERO =       22
# CMO_DMS =      23 
CMO_DMS_GENERIC = 24
CMO_DMS_OF_N_VARIABLES = 25
CMO_RING_BY_NAME = 26
CMO_RECURSIVE_POLYNOMIAL = 27
CMO_LIST_R = 28

CMO_INT32COEFF =  30
CMO_DISTRIBUTED_POLYNOMIAL = 31
# CMO_ZZ_OLD =   32
CMO_POLYNOMIAL_IN_ONE_VARIABLE = 33
CMO_RATIONAL = 34

CMO_64BIT_MACHINE_DOUBLE =   40
CMO_ARRAY_OF_64BIT_MACHINE_DOUBLE =  41
CMO_128BIT_MACHINE_DOUBLE =   42
CMO_ARRAY_OF_128BIT_MACHINE_DOUBLE =  43

CMO_BIGFLOAT =    50
CMO_IEEE_DOUBLE_FLOAT = 51

CMO_INDETERMINATE = 60
CMO_TREE 	=   61
CMO_LAMBDA	=   62    # for function definition


OX_COMMAND =                   513    
OX_DATA =                      514
OX_SYNC_BALL =                 515      # ball to interrupt

#  level 2 stack machine with programming facility. 
OX_START_OF_FUNCTION_BLOCK =    518
OX_END_OF_FUNCTION_BLOCK =      519
OX_ADDRESS =                    520

OX_DATA_WITH_SIZE =              521
OX_DATA_ASIR_BINARY_EXPRESSION = 522  # This number should be changed
OX_DATA_OPENMATH_XML =         523
OX_DATA_OPENMATH_BINARY =      524
OX_DATA_MP =                   525

# OX BYTE command
OX_BYTE_NETWORK_BYTE_ORDER =    0
OX_BYTE_LITTLE_ENDIAN =         1
OX_BYTE_BIG_ENDIAN =         0xff

# ox_function_id.h
SM_popSerializedLocalObject = 258
SM_popCMO = 262
SM_popString = 263    # result ==> string and send the string by CMO

SM_mathcap = 264
SM_pops = 265
SM_setName = 266
SM_evalName = 267 
SM_executeStringByLocalParser = 268 
SM_executeFunction = 269
SM_beginBlock =  270
SM_endBlock =    271
SM_shutdown =    272
SM_setMathCap =  273
SM_executeStringByLocalParserInBatchMode = 274
SM_getsp =   275
SM_dupErrors = 276

SM_DUMMY_sendcmo =  280
SM_sync_ball = 281

SM_control_kill = 1024
SM_control_reset_connection =  1030
SM_control_to_debug_mode = 1025
SM_control_exit_debug_mode = 1026
SM_control_ping =  1027
SM_control_start_watch_thread = 1028
SM_control_stop_watch_thread = 1029

# end of CMO constants

class CMO
  def set_tag(tag)
    @tag = tag
  end
  attr_accessor :tag
end
class CMONull < CMO
  def initialize
    set_tag(CMO_NULL)
  end
end
class CMOInt32 < CMO
  def initialize(i)
    set_tag(CMO_INT32)
    @i = i
  end
  attr_accessor :i
end
class CMOString < CMO
  def initialize(str)
    set_tag(CMO_STRING)
    @str = str
    @len = str.length
  end
  attr_accessor :len, :str
end

class OX < CMO
end

class OXCommand < OX
  def initialize(command)
    set_tag(OX_COMMAND)
    @command = command
  end
  attr_accessor :command
end
class OXData < OX
  def initialize(cmo)
    set_tag(OX_DATA)
    @cmo = cmo
  end
  attr_accessor :cmo
end

class OXSession
  def initialize(
         oxserver = "ox_sm1",
         host = "localhost",
		 byteorder = 0
         )
      @serial = 0

      if ENV.include?("OpenXM_HOME")
         oxhome = ENV["OpenXM_HOME"]+"/"
      else
         oxhome = "/usr/local/OpenXM/"
      end

      oxserver = oxhome+"bin/"+oxserver
      srand()
      @controlport = rand(20000)+1024
 	  @dataport = @controlport+1
      printf("Starting the server %s\n",oxserver)
      $stdout.flush
      controlThread =
      Thread.start {
        printf("Connection from %s, \n", host)
        printf("Waiting a connection to controlport %d, \n", @controlport)
        $stdout.flush
        @controlp = TCPserver.open(@controlport)
        @controlp = controlp.accept
      }
      printf("Waiting a connection to dataport %d, \n", @dataport)
      $stdout.flush
      @datap = TCPserver.open(@dataport)

      sleep 3 # Heuristic wait that TCPserver switches to accept mode.
      printf(oxhome+"\n")
      ox = oxhome+"bin/ox"
      system("oxlog  /usr/X11R6/bin/xterm -geometry 80x24-0-0 -e "+ox+" -ox "+oxserver+" -control "+@controlport.to_s()+" -data "+@dataport.to_s()+" -reverse -pass a &");
      if $? == nil
         printf("failed to start the ox server.\n")
         exit()
      end

#    rescue

    @datap = datap.accept
    Thread#join controlThread

    # byte oder negotiation
    @byteorder = decide_byte_order(byteorder)

    datap.read(2);  ## I do not understand the reason why I need to read
                    ## these extra two bytes.

  end

  attr_accessor :controlp, :datap

  def decide_byte_order(b_or_l)
    if b_or_l == 0
      controlp.read(1)  # do not use @controlp.read(1)
      datap.read(1)
      controlp.putc("\000");
      datap.putc("\000");
      controlp.flush
      datap.flush
      return 0
    end
  end
  
  def send(data)
    case data.tag
    when OX_DATA
      send_ox_tag(OX_DATA)
      send_cmo(data.cmo)
    when OX_COMMAND
      send_ox_tag(OX_COMMAND);
      send_int32(data.command);
    end
  end

  def send_ox_tag(tag)
    send_int32(tag)
    send_int32(@serial)
    @serial += 1;
  end

  def send_int32(n)
    b = n.to_a.pack("N")
    return datap.write(b)
  end

  def send_cmo(data)
    tag = data.tag
    send_int32(tag)
    case tag
    when CMO_NULL
      m = send_cmo_null
    when CMO_INT32
      m = send_cmo_int32(data)
    when CMO_STRING
      m = send_cmo_string(data)
    when CMO_MATHCAP
      m = send_cmo_mathcap(data)
    when CMO_LIST
      m = send_cmo_list(data)
    end
    return m
  end

  def send_cmo_null
    return 0
  end

  def send_cmo_int32(cmo)
    send_int32(cmo.i)
  end

  def send_cmo_string(cmo)
    send_int32(cmo.len)
    datap.write(cmo.str)
  end
    
  def receive
    oxtag = receive_int32
    printf("oxtag = %d \n",oxtag)
    seqNum = receive_int32
    printf("seqNum = %d \n", seqNum)
    $stdout.flush
    if oxtag == OX_DATA then
       tag = receive_int32
    else
       printf("Cannot handle this OX tag %d\n",oxtag)
       $stdout.flush
    end
    printf("cmotag = %d \n",tag)
    $stdout.flush
    case tag  
    when CMO_NULL
      m = receive_cmo_null
    when CMO_INT32
      m = receive_cmo_int32
    when CMO_STRING
      m = receive_cmo_string
    when CMO_MATHCAP
      m = receive_cmo_mathcap
    when CMO_LIST
      m = receive_cmo_list
#     when CMO_MONOMIAL32
#       m = receive_cmo_monomial32
#     when CMO_ZZ
#       m = receive_cmo_zz
#     when CMO_ZERO
#       m = receive_cmo_zero
#     when CMO_DMS_GENERIC
#       m = receive_cmo_dms_generic
#     when CMO_RING_BY_NAME
#       m = receive_cmo_ring_by_name
#     when CMO_DISTRIBUTED_POLYNOMIAL
#       m = receive_cmo_distributed_polynomial
#     when CMO_ERROR2
#       m = receive_cmo_error2
#     when CMO_DATUM
#       m = receive_cmo_datum
#     when CMO_QQ
#       m = receive_cmo_qq
    else
      printf("the CMO (%d) is not implemented.\n", tag)
      $stdout.flush
    end    
    
    return m;
  end
  
  def receive_int32
     hoge = datap.read(4)
     printf("[ ");  
     hoge.each_byte { |c|  printf("%2x ",c) }
     printf(" ]\n");
     return hoge.unpack("N").pop
#    return datap.read(4).unpack("N").pop
  end
  
  def receive_cmo_null
    return CMONull.new
  end
  
  def receive_cmo_int32
    return CMOInt32.new(receive_int32)
  end

  def receive_cmo_string
    size = receive_int32
    s = datap.read(size)
    return(s)
  end

def rpc(s)
# when s is a string
  self.send(OXData.new(CMOString.new(s)))
  self.send(OXCommand.new(SM_executeStringByLocalParser))
  self.send(OXCommand.new(SM_popString))
  return(self.receive())
end
def submit(s)
# when s is a string
  self.send(OXData.new(CMOString.new(s)))
  self.send(OXCommand.new(SM_executeStringByLocalParser))
end

#  attr_accessor :send, :receive
end

# Usage
# % ruby ox-taka.rb
#

s = OXSession.new()

s.submit(" [(oxWatch) 1] extension ");
## sample
a = s.rpc(" 1 1 add ")
printf("The result of  <<  1  1  add >> is  ====> %s\n",a)
## define some useful macros for ruby-sm1
s.submit(" /run {/@@@.run.filename set [(parse) @@@.run.filename pushfile] extension} def");
s.submit(" /quit (Type in ctrl-C to quit.) def ");
$stdout.flush

## sample
##  1 3 add
while 1
  printf("\nruby-sm1>")
  STDOUT.flush
  input = gets
  break if not input
  str = input
  str.chop!
  eval("print(s.rpc(\""+str+"\"))")
end


while 1
  print '> '
  STDOUT.flush
  input = gets
  break if not input
  str = input
  str.chop!
  eval(str)
end