/*
 *      Interactive disassembler (IDA).
 *      Version 3.05
 *      Copyright (c) 1990-95 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              FIDO:   2:5020/209
 *                              E-mail: ig@estar.msk.su
 *
 */

#include "java.hpp"
#include "classfil.hpp"

extern TXS tp_decl[];
extern char *addonce_name;

char *bufbeg;
int bufsize;
ushort maxpos, curpos;
static ushort outcnt;
static char *ref_pos;

#define WARN_SYM     ('#')
#define MIN_ARG_SIZE 3
//----------------------------------------------------------------------
static inline void OutSpace(void)
{
  OutChar(' ');
  ++outcnt;
}
//----------------------------------------------------------------------
static int OutName(ea_t from, int n, ea_t ea, uval_t off)
{
  register char *p;
  if((p = get_name_expr(from, n, ea, off)) == NULL) return(0);
  OutLine(p);
  outcnt += tag_strlen(p);
  return(1);
}

//----------------------------------------------------------------------
inline void out_zero(void)
{
  *get_output_ptr() = '\0';
}

//----------------------------------------------------------------------
static ushort putLine(void)
{
  register color_t ntag = (color_t)0;

  out_zero();
  {
    register char *p = strrchr(bufbeg, COLOR_ON);
    if(p && !strchr(p, COLOR_OFF)) {
      ntag = (color_t)*(p + 1);
      out_tagoff(ntag);
    }
  }
  out_symbol('\\');
  term_output_buffer();
  if(MakeLine(bufbeg, curpos)) return(0);
  init_output_buffer(bufbeg, bufsize);
  curpos = outcnt = 0;
  if(ntag) out_tagon(ntag);
  ref_pos = get_output_ptr();
  return(maxpos);
}

//----------------------------------------------------------------------
inline int CheckLine(ushort size)
{
  if(maxpos - curpos > outcnt + size) return(1);
  return(putLine());
}
//----------------------------------------------------------------------
static int OutIndex(ushort index)
{
  if(!CheckLine(5)) return(1);
  out_tagon(COLOR_ERROR);
  char *p = get_output_ptr();
  OutChar(WARN_SYM);
  OutLong(index, debugmode ? 16 : 10);
  outcnt += get_output_ptr() - p;
  out_tagoff(COLOR_ERROR);
  return(0);
}

//----------------------------------------------------------------------
static int putValue(op_t &x, uchar mode, uchar warn)
{
  register int i;

  if(warn) out_tagon(COLOR_ERROR);
  char *p = get_output_ptr();
  flags_t saved_uFlag = uFlag;
  uFlag = 0;
  OutValue(x, mode);
  uFlag = saved_uFlag;
  out_zero();
  if(!warn) return(tag_strlen(p));
  set_output_ptr(p + (i = tag_remove(p, p, 0)));
  out_tagoff(COLOR_ERROR);
  return i;

}

//----------------------------------------------------------------------
static _OUTPRC_ outProc = putLine;
#if (MIN_ARG_SIZE < 2) || (MIN_ARG_SIZE >= 30)
#error
#endif
static int OutUtf8(ushort index, fmt_t mode, color_t ntag)
{
  register ushort size;

  if((maxpos - curpos - MIN_ARG_SIZE) <= outcnt) {
    if((size = (*outProc)()) == 0) return(1);
  } else size = (maxpos - curpos) - outcnt;

  if(ntag) out_tagon(ntag);
  ref_pos = get_output_ptr();
  if(fmtString(index, size, mode, *outProc) < 0) return(1);
  outcnt += get_output_ptr() - ref_pos;
  if(ntag) out_tagoff(ntag);
  return(0);
}

//----------------------------------------------------------------------
static int OutFlags(ushort flags)
{
  static TXS fn[] = {
                      TXS_DECLARE("public"),
                      TXS_DECLARE("private"),
                      TXS_DECLARE("protected"),
                      TXS_DECLARE("static"),
                      TXS_DECLARE("final"),
                      TXS_DECLARE("synchronized"),
                      TXS_DECLARE("volatile"),
                      TXS_DECLARE("transient"),
                      TXS_DECLARE("native"),
                      TXS_DECLARE("interface"),
                      TXS_DECLARE("abstract")
                    };
  register ushort i;
  register TXS *p;

  for(i = flags & ACC_FULL_MASK, p = fn; i; i >>= 1, p++) if(i & 1) {
    if(!CheckLine(p->size)) return(1);
    outcnt += p->size;
    out_keyword(p->str);
    OutChar(' '); // учтено sizeof за счёт 0-ля :)
  }
  return(0);
}

//----------------------------------------------------------------------
inline bool out_type(op_t &x, bool r)
{
  return !OutUtf8(x._sign, r ? fmt_retsign : fmt_sign, COLOR_KEYWORD);
}

//----------------------------------------------------------------------
static int OutConstant(op_t& x)
{
  register uchar savetype = x.dtyp, r = 0;
  register color_t ntag;

  switch((uchar)x.cp_type) {
    default:
      warning("OC: bad constant type %u", (uchar)x.cp_type);
      break;

    case CONSTANT_Long:
      x.dtyp = dt_qword;
      goto outNum;
    case CONSTANT_Double:
      x.dtyp = dt_double;
      goto outNum;
    case CONSTANT_Integer:
      x.dtyp = dt_dword;
      goto outNum;
    case CONSTANT_Float:
      x.dtyp = dt_float;
outNum:
      outcnt += putValue(x, OOF_NUMBER | OOF_SIGNED | OOFW_IMM, 0);
      break;

    case CONSTANT_String:
      if(OutUtf8(x._name, fmt_string, COLOR_STRING)) return(0);
      break;

    case CONSTANT_Class:
      if(OutUtf8(x._name, (fmt_t)x.addr_shorts.high,
         (fmt_t)x.addr_shorts.high == fmt_fullname ?
            (cmd.xtrn_ip == 0xFFFF ? COLOR_DNAME : COLOR_IMPNAME) :
            COLOR_KEYWORD))                                     return(0);
      break;

    case CONSTANT_InterfaceMethodref:
    case CONSTANT_Methodref:
        ++r;
    case CONSTANT_Fieldref:
        if ( !jasmin() ) out_type(x, r);
        if(x._class != curClass.ThisClass) {
          out_tagon(ntag = COLOR_IMPNAME);
          if(OutUtf8(x._name, fmt_fullname, (color_t)0)) return(0); // Class Name
          OutChar('.');
          ++outcnt;
        } else out_tagon(ntag = COLOR_DNAME);
        if(OutUtf8(x._subnam, fmt_name, (color_t)0)) return(0); // Field
        out_tagoff(ntag);
        if ( r )
          { if( OutUtf8(x._sign, fmt_paramstr, COLOR_KEYWORD) ) return(0); }
        else
          OutChar(' ');
        if ( jasmin() ) out_type(x, r);
        break;
  }
  x.dtyp = savetype;
  return(1);
}

//----------------------------------------------------------------------
bool outop(op_t& x)
{
  register uchar save, warn = 0;

  switch(x.type) {
  case o_void:
    return 0;

  case o_near:
    if(cmd.swit) {              // tableswitch / lookupswitch
      static char defstr[] = "default ";

      out_keyword(defstr);
      outcnt += (sizeof(defstr) - 1);
    }
    if(x.ref) {
      ++warn;
      goto putAddrVal;
    } else {
      if(!OutName(cmd.ea + x.offb, x.n, curSeg.startEA + x.addr, x.addr)) {
        QueueMark(Q_noName, cmd.ea);
putAddrVal:
        outcnt +=
            putValue(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32, warn);
      }
    }
    break;

  case o_imm:
    if((save = x.n) == 0) {
      if(cmd.itype == j_lookupswitch) break;
    }else if(cmd.itype == j_tableswitch) {
      static char to_str[] = "to ";
      out_keyword(to_str);
      outcnt += (sizeof(to_str) - 1);
      x.n = 0;
    }
    if(x.ref == 2) ++warn;
    outcnt +=
        putValue(x, OOFW_IMM | (x.ref ? OOFS_NOSIGN : OOF_SIGNED), warn);
    x.n = save;
    break;

  case o_mem:
    if ( jasmin() ) goto putVarNum;
    if(!x.ref) {
      if(!OutName(cmd.ea + x.offb, x.n, curSeg.DataBase + x.addr, x.addr))
                                                              goto putVarNum;
    } else {
putAddr:
      ++warn;
putVarNum:
      outcnt +=
          putValue(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16, warn);
    }
    break;

  case o_cpool:
    if(!x.cp_ind) {
      static char null_ptr[] = "NULL";
      out_keyword(null_ptr);
      outcnt += (sizeof(null_ptr) - 1);
    } else if(!x.ref) {
             if(!OutConstant(x)) return(0);
           } else goto putAddr;
    break;

  case o_array:
    if(!x.ref) {
      if(!CheckLine(tp_decl[save= (uchar)x.cp_type-T_BOOLEAN].size))return(0);
      outcnt += tp_decl[save].size;
      out_keyword(tp_decl[save].str);
    } else {
      static char tt_bogust[] = "BOGUST_TYPE-";

      if(!CheckLine(sizeof(tt_bogust) + 2)) return(0);
      out_tagon(COLOR_ERROR);
      outcnt += out_snprintf("%c%s%u", WARN_SYM, tt_bogust, (uchar)x.cp_type);
      out_tagoff(COLOR_ERROR);
    }
    break;

  default:
    warning("out: %a: bad optype %d", cmd.ip, x.type);
    break;
  }
  return(1);
}

//----------------------------------------------------------------------
static void _setpos(char *str, size_t strsize, ushort pos)
{
  maxpos = inf.margin;
//  if(maxpos < 32) maxpos = 32;
//  if(maxpos > MAXSTR - 4) maxpos = MAXSTR - 4;

  if(debugmode == 0xFF &&
     inf.s_showpref && inf.margin == 77 && !inf.binSize) maxpos -= gl_psize;
  init_output_buffer(str, strsize);
  bufbeg = str;
  bufsize = strsize;
  curpos = pos;
  outcnt = 0;
}

//----------------------------------------------------------------------
static void instr_beg(char *str, size_t strsize, int mode)
{
  static char *addonce[] = { "", "_w", "_quick", "2_quick", "_quick_w" };

  _setpos(str, strsize, 4);
  ushort saved = 0;
  if ( jasmin() && (cmd.itype == j_ldc1 || cmd.itype == j_ldc2) )
  {
    saved = cmd.itype;
    cmd.itype = j_ldc;
  }
  OutMnem(2, addonce[cmd.wid]);
  if ( saved != 0 ) cmd.itype = saved;
  out_zero();
  if ( mode )
    outcnt = tag_strlen(str);
  else
  {
    char *ptr = str + (outcnt = tag_remove(str, str, 0));
    set_output_ptr(ptr);
    *ptr = '\0';
  }
}

//----------------------------------------------------------------------
void out(void) {
  char str[MAXSTR*2];

  gl_xref = 0;
  instr_beg(str, sizeof(str), 1);
  if(cmd.Op1.type == o_void) {
    register char *p;
    char nbuf[MAXSTR];

    if((char)cmd.Op1.ref > 0 && inf.s_showbads &&
       (p = get_name(BADADDR, cmd.Op1.addr, nbuf, sizeof(nbuf))) != NULL) {
      out_tagon(COLOR_REGCMT);
      outcnt += out_snprintf("%s %s", ash.cmnt, p);
      out_tagoff(COLOR_REGCMT);
    }
  } else if(!out_one_operand(0)) return;

  if(cmd.Op2.type != o_void) {
    OutSpace();
    if(!out_one_operand(1)) return;
  }

  if(cmd.Op3.type != o_void) {
    OutSpace();
    if(!out_one_operand(2)) return;
  }

//   if(isVoid(ea, uFlag, 0)) OutImmChar(cmd.Op1);
//   if(isVoid(ea, uFlag, 1)) OutImmChar(cmd.Op2);
//   if(isVoid(ea, uFlag, 2)) OutImmChar(cmd.Op3);

  out_zero();
  gl_xref = gl_comm = 1;

  if(cmd.swit) {         // tableswitch OR lookupswitch
    uval_t count;
    ea_t addr;
    op_t x;
    uchar warn = 0;

    x.n = 0;   // for base!
    x.flags = OF_SHOW;
    x.dtyp = dt_dword; //???  ЭТО   ???
    x.type = o_imm;    //???  НАДО  ???

    term_output_buffer();
    MakeLine(str, 4);
    init_output_buffer(str, sizeof(str));
    MakeLine(COLSTR("{", SCOLOR_SYMBOL), 4);

    for(addr= cmd.Op2.addr, count= cmd.Op3.value; count; addr +=4, count--) {
      outcnt = 0;
      if(cmd.itype == j_lookupswitch) {
        x.value = get_long(curSeg.startEA + addr); // pairs
        addr += 4;
        outcnt +=
            putValue(x, OOFW_IMM | OOF_NUMBER | OOF_SIGNED | OOFW_32, 0);
        OutSpace();
        out_symbol(':');
        ++outcnt;
        OutSpace();
        while(outcnt % 8) OutSpace();
      }
      if((x.value = cmd.ip + get_long(curSeg.startEA + addr)) >=
         curSeg.CodeSize) {
         ++warn;
         goto putAddrVal2;
      }
      if(!OutName(curSeg.startEA + addr, x.n, curSeg.startEA + x.value, x.value)) {
        QueueMark(Q_noName, cmd.ea);
putAddrVal2:
        outcnt +=
            putValue(x, OOFW_IMM | OOF_NUMBER | OOFS_NOSIGN | OOFW_32, warn);
      }
      term_output_buffer();
      if(MakeLine(str, 6)) return;
      init_output_buffer(str, sizeof(str));
    }
    out_symbol('}');
    term_output_buffer();
  }

  MakeLine(str, curpos);
}

//--------------------------------------------------------------------------
static void myBorder(void)
{
  uchar save = inf.s_limiter;
  inf.s_limiter = LMT_THIN;
  MakeBorder();
  inf.s_limiter = save;
}

//--------------------------------------------------------------------------
void header(void) {
  char str[MAXSTR*2];
  static char fmt1[] = COLSTR("%sJava Virtual Machine. Disassembler mode: %s", SCOLOR_AUTOCMT),
              fm11[] = "Normal",
              fm12[] = "DEBUG",
              fmt3a[]= COLSTR("%sMajor version: %u", SCOLOR_AUTOCMT),
              fmt3b[]= COLSTR("%sMinor version: %u", SCOLOR_AUTOCMT),
              fmt4[] = "Source File  : ";


  if ( !jasmin() )
    MakeLine(COLSTR("/*", SCOLOR_AUTOCMT), 0);
  const char *prefix = jasmin() ? ash.cmnt : "";
  printf_line(0, fmt1, prefix, debugmode ? fm12 : fm11);
  ulong v = (ulong)curClass.MinVers, mv = CURRENT_MAJOR_VERSION;
  if(v & 0x8000) {
    v &= ~0x8000;
    ++mv;
  }
  printf_line(0, fmt3a, prefix, mv);
  printf_line(0, fmt3b, prefix, v);
  if(curClass.SourceName) {
    _setpos(str, sizeof(str), 0);
    out_tagon(COLOR_AUTOCMT);
    OutLine(prefix);
    OutLine(fmt4);
    outcnt = strlen(prefix) + sizeof(fmt4);
    if(OutUtf8(curClass.SourceName, fmt_string, (color_t)0)) return;
    out_tagoff(COLOR_AUTOCMT);
    term_output_buffer();
    if(MakeLine(str, curpos)) return;
  } else MakeNull();
  if ( !jasmin() )
    MakeLine(COLSTR("*/", SCOLOR_AUTOCMT), 0);
}

//--------------------------------------------------------------------------
void footer(void) {
  static char prm[] =
 COLSTR("/* This class has had %lu loading time problem(s) */", SCOLOR_ERROR);

  if ( !jasmin() )
    MakeLine(COLSTR("}", SCOLOR_SYMBOL), 0);
  MakeNull();
  myBorder();
  MakeNull();
  if(curClass.errload) {
    printf_line(-1, prm, curClass.errload);
    MakeNull();
  }
}

//--------------------------------------------------------------------------
// output the method return type
static void out_seg_type(void)
{
  if(curSeg.id.flag & 2) {
    if(OutIndex(curSeg.id.sign)) return;
    OutSpace();
  } else if(OutUtf8(curSeg.id.sign, fmt_retsign, COLOR_KEYWORD)) return; // Type
}

//--------------------------------------------------------------------------
void segstart(ea_t ea)
{
  char str[MAXSTR];  //!!!ATTENTION!!! SIZE (*2)
  uval_t dat;
  static char thr[] = "throws";

  const char *cls_ = jasmin() ? ".class " : "Class ";
  const char *met = jasmin() ? ".method " : "Method";
  _setpos(str, sizeof(str), 2);

  switch(getMySeg(ea)->type) {
    case SEG_CODE:
      {
        register func_t *pt;
        register char   *p;

        if(((pt = get_func(ea)) != NULL) &&
           (((p = get_func_comment(pt, 0)) != NULL ||
              (p = get_func_comment(pt, 1)) != NULL) &&
           generate_big_comment(p, COLOR_REGCMT)))              return;
      }
      out_keyword(met);
      outcnt += strlen(met) + 1;
      if(OutFlags(curSeg.id.access)) return;
      if ( !jasmin() ) out_seg_type();
      if(curSeg.id.flag & 1) {
        if(OutIndex(curSeg.id.name)) return;
      } else if(OutUtf8(curSeg.id.name, fmt_name, COLOR_CNAME)) return; // Method Name
      if((curSeg.id.flag & 2) )
        OutChar(' ');
      else
        if ( OutUtf8(curSeg.id.sign, fmt_paramstr, COLOR_KEYWORD)) return;
      if ( jasmin() ) out_seg_type();
      term_output_buffer();
      if(MakeLine(str, curpos)) return;
      init_output_buffer(str, sizeof(str));
      outcnt = 0;
      if(curSeg.thrNode) {
        register short i, j;

        curpos = 2;
        out_keyword(thr);
        outcnt = sizeof(thr);
        i = (short)netnode(curSeg.thrNode).altval(0);

        for(j = 1; j <= i; j++) {
          OutSpace();
          dat = netnode(curSeg.thrNode).altval(j);
          if(!(ushort)dat) {
            if(OutIndex((ushort)((dat >> 16) & 0xFFFF))) return;
          } else if(OutUtf8((ushort)dat, fmt_fullname, COLOR_IMPNAME)) return;
        }
        term_output_buffer();
        if(MakeLine(str, curpos)) return;
      }
      if(curSeg.stacks) {
        const char *fls = jasmin() ? COLSTR(".limit stack %u", SCOLOR_ASMDIR)
                                   : COLSTR("max_stack %u", SCOLOR_ASMDIR);
        if(printf_line(2, fls, curSeg.stacks)) return;
      }
      if(curSeg.DataSize) {
        const char *flc = jasmin() ? COLSTR(".limit locals %u", SCOLOR_ASMDIR)
                                   : COLSTR("max_locals %u", SCOLOR_ASMDIR);
        if(printf_line(2, flc, curSeg.DataSize)) return;
      }
      if ( !jasmin() )
        MakeLine(COLSTR("{", SCOLOR_SYMBOL), 2);
      break;

    case SEG_IMP:
      curpos = 0;
      out_keyword(cls_);
      outcnt = sizeof(cls_);
      OutFlags(curClass.AccessFlag);
      if(!curClass.ThisClass) {
        OutIndex(curClass.ThisName);
      } else if(OutUtf8(curClass.ThisName,fmt_fullname,COLOR_DNAME)) return;
      term_output_buffer();
      if(MakeLine(str, 0)) return;
      init_output_buffer(str, sizeof(str));
      outcnt = 0;
      if(curClass.SuperClass) {
        const char *extf = jasmin() ? ".super " : "extends ";
        out_keyword(extf);
        outcnt = strlen(extf) + 1;
        if(curClass.SuperClass == 0xFFFF) {
          OutIndex(curClass.SuperName);
        } else if(OutUtf8(curClass.SuperName, fmt_fullname, COLOR_IMPNAME))
                                                                      return;
        term_output_buffer();
        if(MakeLine(str, 0)) return;
        init_output_buffer(str, sizeof(str));
        outcnt = 0;
      }
      if(curClass.impNode) {
        static char imps[] = "implements";
        register ushort i, j;

        out_keyword(imps);
        outcnt = sizeof(imps);
        if((j= (ushort)netnode(curClass.impNode).altval(0)) ==0) destroyed();
        for(i = 1; i <= j; i++) {
          OutSpace();
          dat = netnode(curClass.impNode).altval(i);
          if(!(ushort)dat) {
            if(OutIndex((ushort)((dat >> 16) & 0xFFFF))) return;
          }else if(OutUtf8((ushort)dat, fmt_fullname, COLOR_IMPNAME)) return;
        }
        term_output_buffer();
        MakeLine(str, 0);
      }
      break;

    case SEG_XTRN:
    case SEG_DATA:
      if ( !jasmin() )
        MakeLine(COLSTR("/*", SCOLOR_AUTOCMT), 0);
    default:
      break;
  }
}

//--------------------------------------------------------------------------
static void putAddrNamVal(ushort off)
{
  OutSpace();
  if((ulong)off >= curSeg.CodeSize ||
     !OutName(curSeg.startEA + curSeg.CodeSize, 0, curSeg.startEA + off, off)) {
    register char *p = get_output_ptr();
    OutLong(off, debugmode ? 16 : 10);
    outcnt += get_output_ptr() - p;
  }
}

//--------------------------------------------------------------------------
void segend(ea_t ea)
{
  char str[MAXSTR*2];

  switch(getMySeg(ea-1)->type) {
    case SEG_CODE:
      gl_name = 0;              // for empty method's
      if(curSeg.excNode) {
        Exception ex;
        static char et[] =
          COLSTR("exceptions", SCOLOR_KEYWORD) " " COLSTR("{", SCOLOR_SYMBOL);
        register void *p;
        register ushort i, j;

        MakeNull();
        MakeLine(et, 4);
        if((j= (ushort)netnode(curSeg.excNode).altval(0)) ==0) destroyed();

        for(i = 1; i <= j; i++) {
          _setpos(str, sizeof(str), 6 - 1);
          if((p = netnode(curSeg.excNode).supval(i)) == NULL) destroyed();
          ex = *(Exception *)p;
          putAddrNamVal(ex.start_pc);
          putAddrNamVal(ex.end_pc);
          putAddrNamVal(ex.handler_pc);
          if(ex.catchName != 0) {
            OutSpace();
            if(ex.catchName == 0xFFFF) {
              OutIndex(ex.catchInd);
            }else if(OutUtf8(ex.catchName,fmt_fullname,COLOR_IMPNAME)) return;
          }
          term_output_buffer();
          if(MakeLine(str, curpos)) return;
        }
        if(MakeLine(COLSTR("}", SCOLOR_SYMBOL), 4)) return;
      }

      if ( jasmin() )
        MakeLine(COLSTR(".end method", SCOLOR_KEYWORD), 2);
      else
        MakeLine(COLSTR("}", SCOLOR_SYMBOL), 2);
      break;

    case SEG_XTRN:
    case SEG_DATA:
      if ( !jasmin() )
        MakeLine(COLSTR("*/", SCOLOR_AUTOCMT), 0);
    case SEG_IMP:
    default:
      break;
  }
}

//--------------------------------------------------------------------------
void java_data(ea_t ea)
{
  const char *fld = jasmin() ? ".field " : "Field ";
  const char *cls_ = jasmin() ? ".class " : "Class ";
  char str[MAXSTR*2];
  char nbuf[MAXSTR];
  op_t    x;
  register ushort i;
  register void *p = getMySeg(ea);
  ea_t ip = ea - curSeg.startEA;
  uchar   c, siz = (get_item_end(ea) - ea) == 1;

  gl_name = 1;
  _setpos(str, sizeof(str), 0);
  switch(((segment_t *)p)->type) {

    case SEG_CODE:
      if(ip >= curSeg.CodeSize) return;
      if(get_name(BADADDR, ea, nbuf, sizeof(nbuf))) MakeLine(" ");  //for string delimeter
      if(!siz) {
illcall:
        OutLine(COLSTR("!!!_NOT_SUPPORTED_OUTPUT_MODE_!!!", SCOLOR_ERROR));
      } else {
        static char delm[] = COLSTR("%3u %s 0x%02X", SCOLOR_ERROR);
        curpos = 2;
        c = get_byte(ea);
        out_snprintf(delm, c, ash.cmnt, c);
      }
      break;

    case SEG_DATA:
      if ( jasmin() ) out_line(ash.cmnt, COLOR_AUTOCMT);
      gl_name = 0;
      if((ip = ea - curSeg.DataBase) >= (ulong)curSeg.DataSize) return;
      if(!siz) goto illcall;
      if((p = get_name(BADADDR, ea, nbuf, sizeof(nbuf))) != NULL)
        out_snprintf(COLSTR("%s", SCOLOR_AUTOCMT), p);
      break;

    case SEG_XTRN:
      if(ip > (ulong)curClass.xtrnCnt) return;
      if(!siz) goto illcall;
      if(!ip) {
        printf_line(0, COLSTR("%simporting prototypes", SCOLOR_AUTOCMT), jasmin() ? ash.cmnt : "");
        break; // equivalence - MakeNull(); with comment
      }

      if ( jasmin() ) out_line(ash.cmnt, COLOR_AUTOCMT);
      gl_name = gl_xref = gl_comm = 0;
      {
        register ushort j;
        if((j = (ushort)netnode(curClass.xtrnNode).altval(ip)) == 0 ||
           (p = LoadOpis(j)) == NULL) destroyed();
      }
      x.value = ((ConstOpis *)p)->value;  // name /class
      x.addr =  ((ConstOpis *)p)->value2; // sign/subnam
#ifdef __EA64__
      x.value = make_ulonglong(x.value, x.addr);
#endif
      switch(x.cp_type = ((ConstOpis *)p)->type) {
        default:
          destroyed();

        case CONSTANT_Class:
          out_keyword(cls_);
          outcnt = sizeof(cls_);
          x.addr_shorts.high = (ushort)
                                ((((ConstOpis *)p)->flag & HAS_CLASS_NAME) ?
                                               fmt_fullname : fmt_signclass);
          break;

        case CONSTANT_Fieldref:
        case CONSTANT_InterfaceMethodref:
        case CONSTANT_Methodref:
          curpos = 2;
          break;
      }
      if(!OutConstant(x)) return;
      break;

    case SEG_IMP:
      if(ip > (ulong)curClass.FieldCnt) return;
      if(!siz) goto illcall;
      if(!ip) {
        gl_name = 0;
        if ( !jasmin() )
          MakeLine(COLSTR("{", SCOLOR_SYMBOL), 0);
        return;
      }
      gl_name = gl_comm = 0;
      curpos = 2;
      gl_xref = 0;
      out_keyword(fld);
      outcnt = strlen(fld) + 1;
      if((p = netnode(curClass.ClassNode).supval(ip)) == NULL) destroyed();
      curField = *((FieldInfo *)p);
      OutFlags(curField.id.access);
      if(curField.id.flag & 2) {
        if(OutIndex(curField.id.sign)) return;
        OutSpace();
      } else if(OutUtf8(curField.id.sign, fmt_sign, COLOR_KEYWORD)) return; // Type
      if(curField.id.flag & 1) {
        if(OutIndex(curField.id.name)) return;
      } else if(OutUtf8(curField.id.name, fmt_name, COLOR_DNAME)) return;
      if(curField.valNode) {
        op_t x;
        ushort valcnt;

        if((valcnt = (ushort)netnode(curField.valNode).altval(0)) == 0)
                                                              destroyed();
        x.n = 0;
        x.flags = OF_SHOW;
        x.type = o_imm;

        if(!CheckLine(3)) return;
        OutSpace();
        out_symbol('=');
        ++outcnt;
        OutSpace();
        for(i = 1; ; i++) {
          char tmpstr[80], *u_save;

          if((p = netnode(curField.valNode).supval(i)) == NULL) {
            if((ushort)(ip = netnode(curField.valNode).altval(i)) != 0xFFFF)
                                                                  destroyed();
            if(OutIndex((ushort)((ip >> 16) & 0xFFFF))) return;
          } else switch(((ConstOpis *)p)->type) {
            case CONSTANT_Long:
              x.dtyp = dt_qword;
              goto two_w;
            case CONSTANT_Double:
              x.dtyp = dt_float;
two_w:
              x.addr = ((ConstOpis *)p)->value2;
              x.value = ((ConstOpis *)p)->value;
#ifdef __EA64__
              x.value = make_ulonglong(x.value, x.addr);
#endif
              goto one_w;
            case CONSTANT_Float:
              x.dtyp = dt_float;
              x.value = ((ConstOpis *)p)->value;
              goto one_w;
            case CONSTANT_Integer:
              x.dtyp = dt_dword;
              x.value = ((ConstOpis *)p)->value;
one_w:
              u_save = get_output_ptr();
              init_output_buffer(tmpstr, sizeof(tmpstr));
              {
                register int j =
                    putValue(x, OOF_NUMBER | OOF_SIGNED | OOFW_IMM, 0);
                init_output_buffer(str, sizeof(str));
                set_output_ptr(u_save);
                if(!CheckLine(j)) return;
                outcnt += j;
              }
              OutLine(tmpstr);
              break;

            case CONSTANT_String:
              if(!CheckLine(2)) return;
              if(OutUtf8(((ConstOpis *)p)->_name, fmt_string, COLOR_STRING))
                                                                      return;
              break;

            default:
              not_compat();
              break;
          }

          if(i >= valcnt) break;
          if(!CheckLine(2)) return;
          out_symbol(',');
          ++outcnt;
          OutSpace();
        } // end value 'for'
      } // end if(valuecnt)
    default:
      break;
  }
  gl_xref = gl_comm = 1;
  term_output_buffer();
  MakeLine(str, curpos);
}

//--------------------------------------------------------------------------
//  Procedures for "Enter"
//--------------------------------------------------------------------------
static const char *searchstr;
static ushort savmax, fullpos;
//--------------------------------------------------------------------------
static ushort checker(void)
{
  register const char *p;

  *get_output_ptr() = '\0';
  init_output_buffer(bufbeg, bufsize);
  if((p = strstr(searchstr, bufbeg)) != NULL) {
    savmax = (ushort)(p - searchstr);
    return(maxpos = 0);
  }
  curpos = outcnt = 0;
  fullpos += maxpos;
  return(maxpos = savmax);
}

//--------------------------------------------------------------------------
ea_t get_ref_addr(ea_t ea, const char *string, int pos)
{
  char str[MAXSTR];   //!!!ATTENTION!!! SIZE (*2)
  ushort namepos, parampos;
  short  require;
  register int r;
  register uchar *p;

  if((unsigned)strlen(string) <= (unsigned)pos) return(BADADDR);

  if(((p = (uchar *)strstr(string, ash.cmnt)) != NULL &&
      (int)(p - (uchar *)string) <= pos)
     || getMySeg(ea)->type != SEG_CODE
     || (ea- curSeg.startEA) >=curSeg.CodeSize || !ua_ana0(ea)) goto textAns;

  if(cmd.Op1.type == o_void && cmd.Op1.ref) {
    instr_beg(str, sizeof(str), 0);
    if((p = (uchar *)strstr(string, str)) == NULL) goto textAns;
    if((r = (int)(p - (uchar *)string)) > pos &&
       string[pos] != ' ') goto textAns;
    if(r + ((ushort)(strchr(str, '_') - str) + 1) != pos) return(BADADDR);
    return(cmd.Op1.addr);
  }

  if(cmd.Op1.type != o_cpool || !cmd.Op1.cp_ind || cmd.Op1.ref) goto textAns;

  instr_beg(str, sizeof(str), 0);
  savmax = maxpos;
  maxpos -= outcnt;
  init_output_buffer(bufbeg, bufsize);
  outcnt = 0;
  searchstr = string;
  outProc = checker;
  fullpos = r = 0;
  namepos = parampos = 0xFFFF;
  require = 1;
  switch((uchar)cmd.Op1.cp_type) {
    case CONSTANT_InterfaceMethodref:
    case CONSTANT_Methodref:
        ++r;
        require = -1;
    case CONSTANT_Fieldref:
      if ( !jasmin() )
        if(OutUtf8(cmd.Op1._sign, r ? fmt_retsign : fmt_sign,(color_t)0)) break;//fnd(Sign)
      namepos = fullpos + outcnt;
      if(cmd.Op1._class != curClass.ThisClass) {
        if(OutUtf8(cmd.Op1._name, fmt_fullname, (color_t)0)) break;    // found (Class)
        OutChar('.');
        ++outcnt;
      }
      if(OutUtf8(cmd.Op1._subnam, fmt_name, (color_t)0)) break;        // found (Field)
      parampos = fullpos + outcnt;
      if ( r )
        {if(OutUtf8(cmd.Op1._sign, fmt_paramstr, (color_t)0)) break;} // found (param)
      else
        OutChar(' ');
      if ( jasmin() )
        if(OutUtf8(cmd.Op1._sign, r ? fmt_retsign : fmt_sign,(color_t)0)) break;//fnd(Sign)
      goto doout;

    case CONSTANT_Class:
      require = 0;
      namepos = 0;
      if(OutUtf8(cmd.Op1._name, (fmt_t)cmd.Op1.addr_shorts.low, (color_t)0))
                                                                 break;//fnd?
doout:
      checker();
    default:
      break;
  }
  outProc = putLine;
  if(maxpos || savmax > (ushort)pos || savmax + strlen(str) <= (unsigned)pos)
                                                            goto textAns;//\\?

  r = pos + fullpos - savmax + curpos - 4;
  if(parampos <= r) {
    if(r == parampos ||
       (!savmax && (unsigned)r == (fullpos + strlen(bufbeg) - 1)))
                                                             return(BADADDR);
// return textAns //msg("found param %u\n", r-parampos-1);
  } else if(namepos <= r) {
    if(cmd.Op1._class != curClass.ThisClass) {
      if(cmd.xtrn_ip) return(cmd.xtrn_ip == 0xFFFF ? curClass.startEA :
                                              curClass.xtrnEA + cmd.xtrn_ip);
//\\ может лучше на TextAns?
      return(BADADDR);
    } else {
      if(!require) {
        if(cmd.Op1.addr_shorts.high == (ushort)fmt_fullname)
                                                  return(curClass.startEA);
//\\ Это выход из cast/instanceof - если бывает на себя, то обработать
        return(BADADDR); //?
      }
      return(SearchFM(cmd.Op1._subnam, cmd.Op1._sign, &require));
    }
  } else {
    if(r == (namepos - 1)) return(BADADDR);
// return textAns //msg("prototype\n");
  }

textAns:
  if((r = pos) == 0) return(BADADDR);
  *addonce_name = '.';
  p = (uchar *)&string[r];
  if(!strchr(NameChars, *p)) {
    *addonce_name = '\0';
    return(BADADDR);
  }
  do if(!strchr(NameChars, *--p)) break; while(--r);
  namepos = r;
  for(p=(uchar *)&string[r=pos+1];*p;r++) if(!strchr(NameChars,*p++)) break;
  *addonce_name = '\0';
  if(*p == '\\' && !*(p+1)) return(BADADDR); //\\+++ не обраб. перенос?
  qstrncpy(str, &string[namepos], r -= namepos);
  ea = get_name_ea(BADADDR, str);
  return(ea);
}

//--------------------------------------------------------------------------
