void near * _vector_vnew_(void near *ptr, // address of array, 0 means allocate size_t size, // size of each object unsigned count, // how many objects unsigned mode, // actual type of constructor ... ) /* This routine is used to initialize an array of class type. If ptr is NULL, it allocates the space for the array first. Since the constructor for the class may be of either memory model, and take an argument of any memory model, we are forced to pass a mode parameter to tell us how to cast it. Since we must pass a near pointer for near functions and a far call for far functions, we can't even know the argument type until runtime, so we have to use varargs to get at it. This version passes the second argument needed for a class with virtual bases. If the constructor pointer is NULL no constructors are called. The interpretation of the mode parameter is: far function 0x01 VFARCALL pascal call 0x02 VPASCAL far pointer 0x04 VFARPTR deallocate 0x08 VDEALLOC stored count 0x10 VSTORECNT fastcall 0x20 VFASTCALL huge vector 0x40 VHUGEVECT fastthis 0x80 VFASTTHIS this last 0x100 VTHISLAST */ { #if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) abort(); return 0; #else va_list ap; // for access to parameters consvNNC np; // near call version consvFNC fp; // far call version int construct = 1; // flag whether to call constructors va_start(ap, mode); if (mode & VFARCALL) { fp = va_arg(ap, consvFNC); if (!fp) construct = 0; } else { np = va_arg(ap, consvNNC); if (!np) construct = 0; } if( ptr == 0 ) { unsigned long Length = size * count; if (mode & VSTORECNT) // stored count Length += sizeof(count); // check that additional bytes don't make it go over 64K if (Length > 0xFFFF) return 0; ptr = operator new((unsigned)Length); if (!ptr) return 0; // have ptr at either final location or count before if (mode & VSTORECNT) // store count { *(unsigned *)ptr = count; ((unsigned *)ptr)++; } } mode &= VCALLTYPE; // strip out all flags except call type if (mode & VFASTTHIS) // this-last has no effect with fast-this mode &= ~(VTHISLAST); if (construct) { for( char *p = (char *) ptr; count-- > 0; p += size ) switch (mode) { case 0: (*(consvNNC) np)((void near *) p, 0); break; case (VFARCALL): (*(consvFNC) fp)((void near *) p, 0); break; case (VPASCAL): (*(consvNNP) np)((void near *) p, 0); break; case (VPASCAL | VTHISLAST): (*(consvNNPL) np)(0, (void near *) p); break; case (VFARCALL | VPASCAL): (*(consvFNP) fp)((void near *) p, 0); break; case (VFARCALL | VPASCAL | VTHISLAST): (*(consvFNPL) fp)(0, (void near *) p); break; case (VFASTCALL): (*(consvNNF) np)((void near *) p, 0); break; case (VFASTCALL | VTHISLAST): (*(consvNNFL) np)(0, (void near *) p); break; case (VFARCALL | VFASTCALL): (*(consvFNF) fp)((void near *) p, 0); break; case (VFARCALL | VFASTCALL | VTHISLAST): (*(consvFNFL) fp)(0, (void near *) p); break; case (0 | VFASTTHIS): LOAD_NEAR_THIS(p); (*(consvNNCT) np)(0); END_NEAR_THIS(); break; case (VFARCALL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(consvFNCT) fp)(0); END_NEAR_THIS(); break; case (VPASCAL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(consvNNPT) np)(0); END_NEAR_THIS(); break; case (VFARCALL | VPASCAL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(consvFNPT) fp)(0); END_NEAR_THIS(); break; case (VFASTCALL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(consvNNFT) np)(0); END_NEAR_THIS(); break; case (VFARCALL | VFASTCALL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(consvFNFT) fp)(0); END_NEAR_THIS(); break; default: abort(); break; } } return ptr; #endif }
void _vector_delete_(void near *ptr, // address of array (always needed) size_t size, // size of each object unsigned count, // how many objects unsigned mode, // How to call ... ) /* This routine is used to destroy an array of class type. If mode is set, it deallocates the space for the array afterwards. Since the destructor for the class may be of either memory model, and take an argument of any memory model, we are forced to pass a mode parameter to tell us how to cast it. Since we must pass a near pointer for near functions and a far pointer for far functions, we can't even know the argument type until runtime, so we have to use varargs to get at it. If the destructor pointer is NULL no destructors are called. The interpretation of the mode parameter is: far function 0x01 VFARCALL pascal call 0x02 VPASCAL far pointer 0x04 VFARPTR deallocate 0x08 VDEALLOC stored count 0x10 VSTORECNT fastcall 0x20 VFASTCALL huge vector 0x40 VHUGEVECT fastthis 0x80 VFASTTHIS this last 0x100 VTHISLAST */ { #if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) abort(); #else va_list ap; // for access to parameters destNNC np; // near call version destFNC fp; // far call version int destruct = 1; // flag whether to call destructors if (!ptr) return; va_start(ap, mode); if (mode & VFARCALL) { fp = va_arg(ap, destFNC); if (!fp) destruct = 0; } else { np = va_arg(ap, destNNC); if (!np) destruct = 0; } if (mode & VSTORECNT) // if stored count count = *((unsigned *) ((char *)ptr - sizeof(count))); if (destruct) { // get call type unsigned CallType = mode & VCALLTYPE; // this-last has no effect with fast-this if (CallType & VFASTTHIS) CallType &= ~(VTHISLAST); for(char near *p = (char near *) ptr + size * (count - 1); count-- > 0; p -= size) { switch (CallType) { case 0: (*(destNNC) np)((void near *) p, 2); break; case (VFARCALL): (*(destFNC) fp)((void near *) p, 2); break; case (VPASCAL): (*(destNNP) np)((void near *) p, 2); break; case (VPASCAL | VTHISLAST): (*(destNNPL) np)(2, (void near *) p); break; case (VFARCALL | VPASCAL): (*(destFNP) fp)((void near *) p, 2); break; case (VFARCALL | VPASCAL | VTHISLAST): (*(destFNPL) fp)(2, (void near *) p); break; case (VFASTCALL): (*(destNNF) np)((void near *) p, 2); break; case (VFASTCALL | VTHISLAST): (*(destNNFL) np)(2, (void near *) p); break; case (VFARCALL | VFASTCALL): (*(destFNF) fp)((void near *) p, 2); break; case (VFARCALL | VFASTCALL | VTHISLAST): (*(destFNFL) fp)(2, (void near *) p); break; case (0 | VFASTTHIS): LOAD_NEAR_THIS(p); (*(destNNCT) np)(2); END_NEAR_THIS(); break; case (VFARCALL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(destFNCT) fp)(2); END_NEAR_THIS(); break; case (VPASCAL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(destNNPT) np)(2); END_NEAR_THIS(); break; case (VFARCALL | VPASCAL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(destFNPT) fp)(2); END_NEAR_THIS(); break; case (VFASTCALL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(destNNFT) np)(2); END_NEAR_THIS(); break; case (VFARCALL | VFASTCALL | VFASTTHIS): LOAD_NEAR_THIS(p); (*(destFNFT) fp)(2); END_NEAR_THIS(); break; default: abort(); break; } } } if (mode & VDEALLOC) { if (mode & VSTORECNT) // stored count ptr = (char *)ptr - sizeof(count); operator delete((void near *)ptr); } #endif }
void _vector_applyv_(void far * dest, // address of destination array void far * src, // address of source array size_t size, // size of each object unsigned count, // number of objects unsigned mode, // type of function to call ... ) /* This routine is used to copy an array of class type. Since the routine used for the class may be of either memory model, and take arguments of any memory model, we are forced to pass a mode parameter to tell us how to cast it. Since we must pass a near pointer for near functions and a far call for far functions, we can't even know the argument type until runtime, so we have to use varargs to get at it. We do assume that both source and destination have the same distance modifier, and the compiler enforces that. The interpretation of the mode parameter is: far function 0x01 VFARCALL pascal call 0x02 VPASCAL far pointer 0x04 VFARPTR fastcall 0x20 VFASTCALL fastthis 0x80 VFASTTHIS this last 0x100 VTHISLAST */ { va_list ap; /* for access to parameters */ appvNNC np; /* Near pointer version */ appvFNC fp; /* Far pointer version */ va_start(ap, mode); if (mode & 1) fp = va_arg(ap, appvFNC); else np = va_arg(ap, appvNNC); if (mode & VFASTTHIS) // this-last has no effect with fast-this mode &= ~(VTHISLAST); do { switch (mode) { case 0: (*(appvNNC) np)((void near *)dest, 0, (void near *)src); break; case (VFARCALL): (*(appvFNC) fp)((void near *)dest, 0, (void near *)src); break; case (VPASCAL): (*(appvNNP) np)((void near *)dest, 0, (void near *)src); break; case (VPASCAL | VTHISLAST): (*(appvNNPL) np)(0, (void near *)src, (void near *)dest); break; case (VFARCALL | VPASCAL): (*(appvFNP) fp)((void near *)dest, 0, (void near *)src); break; case (VFARCALL | VPASCAL | VTHISLAST): (*(appvFNPL) fp)(0, (void near *)src, (void near *)dest); break; case (VFASTCALL): (*(appvNNF) np)((void near *)dest, 0, (void near *)src); break; case (VFASTCALL | VTHISLAST): (*(appvNNFL) np)(0, (void near *)src, (void near *)dest); break; case (VFARCALL | VFASTCALL): (*(appvFNF) fp)((void near *)dest, 0, (void near *)src); break; case (VFARCALL | VFASTCALL | VTHISLAST): (*(appvFNFL) fp)(0, (void near *)src, (void near *)dest); break; case (VFARPTR): (*(appvNFC) np)((void far *)dest, 0, (void far *)src); break; case (VFARCALL | VFARPTR): (*(appvFFC) fp)((void far *)dest, 0, (void far *)src); break; case (VFARPTR | VPASCAL): (*(appvNFP) np)((void far *)dest, 0, (void far *)src); break; case (VFARPTR | VPASCAL | VTHISLAST): (*(appvNFPL) np)(0, (void far *)src, (void far *)dest); break; case (VFARCALL | VFARPTR | VPASCAL): (*(appvFFP) fp)((void far *)dest, 0, (void far *)src); break; case (VFARCALL | VFARPTR | VPASCAL | VTHISLAST): (*(appvFFPL) fp)(0, (void far *)src, (void far *)dest); break; case (VFARPTR | VFASTCALL): (*(appvNFF) np)((void far *)dest, 0, (void far *)src); break; case (VFARPTR | VFASTCALL | VTHISLAST): (*(appvNFFL) np)(0, (void far *)src, (void far *)dest); break; case (VFARCALL | VFARPTR | VFASTCALL): (*(appvFFF) fp)((void far *)dest, 0, (void far *)src); break; case (VFARCALL | VFARPTR | VFASTCALL | VTHISLAST): (*(appvFFFL) fp)(0, (void far *)src, (void far *)dest); break; case (0 | VFASTTHIS): LOAD_NEAR_THIS(dest); (*(appvNNCT) np)(0, (void near *)src); END_NEAR_THIS(); break; case (VFARCALL | VFASTTHIS): LOAD_NEAR_THIS(dest); (*(appvFNCT) fp)(0, (void near *)src); END_NEAR_THIS(); break; case (VPASCAL | VFASTTHIS): LOAD_NEAR_THIS(dest); (*(appvNNPT) np)(0, (void near *)src); END_NEAR_THIS(); break; case (VFARCALL | VPASCAL | VFASTTHIS): LOAD_NEAR_THIS(dest); (*(appvFNPT) fp)(0, (void near *)src); END_NEAR_THIS(); break; case (VFASTCALL | VFASTTHIS): LOAD_NEAR_THIS(dest); (*(appvNNFT) np)(0, (void near *)src); END_NEAR_THIS(); break; case (VFARCALL | VFASTCALL | VFASTTHIS): LOAD_NEAR_THIS(dest); (*(appvFNFT) fp)(0, (void near *)src); END_NEAR_THIS(); break; case (VFARPTR | VFASTTHIS): LOAD_FAR_THIS(dest); (*(appvNFCT) np)(0, (void far *)src); END_FAR_THIS(); break; case (VFARCALL | VFARPTR | VFASTTHIS): LOAD_FAR_THIS(dest); (*(appvFFCT) fp)(0, (void far *)src); END_FAR_THIS(); break; case (VFARPTR | VPASCAL | VFASTTHIS): LOAD_FAR_THIS(dest); (*(appvNFPT) np)(0, (void far *)src); END_FAR_THIS(); break; case (VFARCALL | VFARPTR | VPASCAL | VFASTTHIS): LOAD_FAR_THIS(dest); (*(appvFFPT) fp)(0, (void far *)src); END_FAR_THIS(); break; case (VFARPTR | VFASTCALL | VFASTTHIS): LOAD_FAR_THIS(dest); (*(appvNFFT) np)(0, (void far *)src); END_FAR_THIS(); break; case (VFARCALL | VFARPTR | VFASTCALL | VFASTTHIS): LOAD_FAR_THIS(dest); (*(appvFFFT) fp)(0, (void far *)src); END_FAR_THIS(); break; default: abort(); break; } (char far *) dest += size; (char far *) src += size; } while (--count > 0); }