/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
   USA

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include <cstddef>
#include "_rtti.h"

// don't write to these, there is no space allocated
//extern const void * __code_seg_start, *__code_seg_end ;

static int findoffs(CLASSXCEPT *__newxt, CLASSXCEPT *__oldxt, int oldoffs)
{
   CLASSXCEPTREF *xr = (CLASSXCEPTREF *)((unsigned char *)(__newxt + 1) + __newxt->name[0]) ;
   while (xr->flags) {
      if (xr->flags & XD_CL_BASE) {
         int offset ;
         if (xr->xt == __oldxt) {
            offset =  xr->offset ;
            return offset + oldoffs ;
         } else {
            offset = findoffs(xr->xt,__oldxt,xr->offset) ;
            if (offset != -1)
               return offset + oldoffs ;
         }
      }
      xr = (CLASSXCEPTREF *)((unsigned char *)(xr + 1) + (xr->flags & XD_X_MASK)) ;
   }
   return -1 ;
}
void * _RTL_FUNC __dynamic_cast(void *__instance, void *__oldxt, void *__newxt)
{
   int offset = 0 ;

   // try to find an offsset for the func
   offset = findoffs((CLASSXCEPT*)__newxt, (CLASSXCEPT *)__oldxt,0) ;
   // if we found it
   if (offset != -1) {
      CLASSXCEPT *xoldxt ;

      // find the XT for this class
      int *temp = *(int **)__instance ; // vtab
      while (temp[-1]) // find beginning of this vtab
         temp = (int *)((unsigned char *)temp - temp[-1]) ;
      temp = temp - VTAB_XT_OFFS/sizeof(int *) ; // point to xt
      xoldxt = *(CLASSXCEPT **)temp ; // get xt
      if (xoldxt == (CLASSXCEPT *)__newxt) { // exact match, return the new instance ptr
         return (void *)((unsigned char *)__instance - offset) ;
      } else {
         // else check to make sure the new type is a base of the final type
         int offset1 = findoffs(xoldxt,(CLASSXCEPT*)__newxt,0) ;
         if (offset1 != -1)
            return (void *)((unsigned char *)__instance - offset + offset1) ;
      }
   }
   // no match, signal failure
   return 0 ;
}