RubyでHSPのオブジェクトファイルのインスペクタを作り中:3
行番号の表示とか。そろそろメソッド分割しないとやばい。
TYPENAMES = %w( TYPE_MARK TYPE_VAR TYPE_STRING TYPE_DNUM TYPE_INUM TYPE_STRUCT TYPE_XLABEL TYPE_LABEL TYPE_INTCMD TYPE_EXTCMD TYPE_EXTSYSVAR TYPE_CMPCMD TYPE_MODCMD TYPE_INTFUNC TYPE_SYSVAR TYPE_PROGCMD TYPE_DLLFUNC TYPE_DLLCTRL TYPE_USERDEF ) TYPENAMES.each_with_index do |typename, i| Object.const_set( typename, i ) end INTCMDS = %w( onexit onerror onkey onclick oncmd * * * * * * * * * * * * exist delete mkdir chdir dirlist bload bsave bcopy memfile poke wpoke lpoke getstr chdpm memexpand memcpy memset notesel noteadd notedel noteload notesave randomize noteunsel noteget ) EXTCMDS = %w( button chgdisp exec dialog * * * * mmload mmplay mmstop mci pset pget syscolor mes title pos circle cls font sysfont objsize picload color palcolor palette redraw width gsel gcopy gzoom gmode bmpsave hsvcolor getkey listbox chkbox combox input mesbox buffer screen bgscr mouse objsel groll line clrobj boxf objprm objmode stick grect grotate gsquare ) EXTSYSVARS = %w( mousex mousey mousew hwnd hinstance hdc ) EXTSYSVARS[0x100,0] = %w( ginfo objinfo dirinfo sysinfo ) CMPCMDS = %w( if else ) INTFUNCS = %w( int rnd strlen length length2 length3 length4 vartype gettime peek wpeek lpeek varptr varuse noteinfo instr abs limit ) INTFUNCS[0x100,0] = %w( str strmid strf getpath ) INTFUNCS[0x180,0] = %w( sin cos tan atan sqrt double absf expf logf limitf ) SYSVARS = %w( system hspstat hspver stat cnt err strsize looplev sublev iparam wparam lparam refstr refdval ) PROGCMDS = %w( goto gosub return break repeat loop continue wait await dim sdim foreach * dimtype dup dupptr end stop newmod * delmod mref run exgoto on mcall assert logmes ) DLLCTRLS = %w( newcom querycom delcom cnvstow comres axobj winobj sendmsg comevent comevarg sarrayconv ) DLLCTRLS[0x100,0] = %w( callfunc cnvwtos comevdisp libptr ) RESERVEDS = { TYPE_INTCMD => INTCMDS, TYPE_EXTCMD => EXTCMDS, TYPE_EXTSYSVAR => EXTSYSVARS, TYPE_CMPCMD => CMPCMDS, TYPE_INTFUNC => INTFUNCS, TYPE_SYSVAR => SYSVARS, TYPE_PROGCMD => PROGCMDS, TYPE_DLLCTRL => DLLCTRLS } def get_ds( ds, i ) ds[i..-1].split("\0")[0] end obj = ARGF.read max_val = obj[8,4].unpack('i')[0] pt_cs, max_cs, pt_ds, max_ds, pt_ot, max_ot, pt_dinfo, max_dinfo = obj[16,32].unpack('i8') cs = obj[pt_cs, max_cs] ds = obj[pt_ds, max_ds] ot = obj[pt_ot, max_ot] dinfo = obj[pt_dinfo, max_dinfo] labels = {} ot.unpack( 'i*' ).each_with_index do |ofs,id| if labels[ofs] labels[ofs] << id else labels[ofs] = [id] end end varnames = [] lines = [] i = 0 while i < max_dinfo && dinfo[i] != 255 ofs = dinfo[i] i += 1 case ofs when 254 filename = get_ds( ds, (dinfo[i,3]+"\0").unpack('i')[0] ) lineno = dinfo[i+3,2].unpack('s')[0] lines << [filename, lineno] i += 3 + 2 when 253 varnames << get_ds( ds, (dinfo[i,3]+"\0").unpack('i')[0] ) i += 3 + 2 when 252 lines << dinfo[i,2].unpack('s')[0] i += 2 else lines << ofs end end filename = nil lineno = 1 lines_ptr = 0 i = 0 offset = 0 while i < max_cs loop do if Array === lines[lines_ptr] filename, lineno = lines[lines_ptr] lines_ptr += 1 next end break unless lines[lines_ptr] && offset/2 >= lines[lines_ptr] offset = 0#-= lines[lines_ptr] lineno += 1 lines_ptr += 1 end if labels[i/2] labels[i/2].each do |id| puts "*label#{id}" end end print "#{filename}##{lineno} " c = *cs[i,2].unpack('s') i += 2 offset += 2 type = c & 0x1fff ex1 = c & 0x2000 != 0 ex2 = c & 0x4000 != 0 if c & 0x8000 != 0 code = cs[i,4].unpack('i')[0] i += 4 offset += 4 else code = cs[i,2].unpack('S')[0] i += 2 offset += 2 end print "#{TYPENAMES[type]}" case type when TYPE_MARK if (0x20..0x7e) === code print "('#{code.chr}')" else print '(0x%02x)' % code end when TYPE_VAR print '(%p)' % ( varnames[code] || code ) when TYPE_STRING print '(%p)' % get_ds( ds, code ) when TYPE_DNUM print '(%s)' % ds[code,8].unpack('d') when TYPE_INUM print "(#{code})" when *RESERVEDS.keys if RESERVEDS[type][code] print '(%s)' % RESERVEDS[type][code] else print '(0x%x)' % code end if type == TYPE_CMPCMD print ' ', cs[i,2].unpack('s')[0] i += 2 offset += 2 end else print '(0x%x)' % code end print ' ex1' if ex1 print ' ex2' if ex2 puts end