/***************************************************************************
*
* Module Name: basemac.h
*
* OS/2 public header file.
*
* Copyright (c) 1987 - 1992  IBM Corporation
*/

/*** Generic macros
 */

#define NElements(array) ((sizeof array)/(sizeof array[0]))

#define SWAP(a,b,tmp)   (tmp=b, b=a, a=tmp)


// Assorted macros from STDLIB.H...
#define min(a, b)       (((a) < (b))? (a) : (b))
#define max(a, b)       (((a) > (b))? (a) : (b))


// To extract offset or selector from a FAR32 (16:32) pointer
#define OFFSETOF32(p)   (((PDWORD)&(p))[0])
#define SEGMENTOF32(p)  (((PWORD)&(p))[2])

// To extract offset or selector from any FAR (16:16) pointer
#define OFFSETOF16(p)   (((PWORD)&(p))[0])
#define SEGMENTOF16(p)  (((PWORD)&(p))[1])

// For now, the default operators assume they're working on 16:16 pointers
#define OFFSETOF        OFFSETOF16
#define SEGMENTOF       SEGMENTOF16

// To convert a tiled 16:16 address to a 0:32 address
#define MAKEFLATP(fp)   ((PVOID)((SEGMENTOF(fp)&~7)<<13 | OFFSETOF(fp)))

// To extract any byte, word, dword, pfn, etc. from the given item
#define BYTEOF(p,i)     (((PBYTE)&(p))[i])
#define WORDOF(p,i)     (((PWORD)&(p))[i])
#define DWORDOF(p,i)    (((PDWORD)&(p))[i])
#define PFNOF(p,i)      (((PPFN)&(p))[i])

// To test/set bits
#define TESTBIT(i,b)    (((i)&(b)) != 0)
#define SETBIT(i,b,f)   (i = ((i)&~(b)) | (b)*(!!(f)))
#define SETBITB(i,b,f)  (i = (BYTE)(((i)&~(b)) | (b)*(!!(f))))

// ZEROBITS returns the number of low zero bits in a 32-bit constant
#define _Z2(l)          ((l)&1?0:(l)&2?1:2)
#define _Z4(l)          ((l)&3?_Z2(l):_Z2((l)>>2)+2)
#define _Z8(l)          ((l)&15?_Z4(l):_Z4((l)>>4)+4)
#define _Z16(l)         ((l)&255?_Z8(l):_Z8((l)>>8)+8)
#define _Z32(l)         ((l)&65535?_Z16(l):_Z16((l)>>16)+16)
#define ZEROBITS(l)     _Z32(l)

// LOG2 returns the nearest base-2 log of a 32-bit constant, rounded up
#define _L2(l)          ((l)&~1?2:(l)&1)
#define _L4(l)          ((l)&~3?_L2((l)>>2)+2:_L2(l))
#define _L8(l)          ((l)&~15?_L4((l)>>4)+4:_L4(l))
#define _L16(l)         ((l)&~255?_L8((l)>>8)+8:_L8(l))
#define _L32(l)         ((l)&~65535?_L16((l)>>16)+16:_L16(l))
#define LOG2(l)         _L32((l)-1)

// EXP2 returns 2 raised to the given power
#define EXP2(l)         (1 << (l))

// Unit conversion macros
#define KBFROMBYTES(nb)         (((nb)+KSIZE-1)/KSIZE)
#define BYTESFROMKB(nkb)        ((nkb)*KSIZE)
#define PAGESFROMBYTES(nb)      (((nb)+PAGESIZE-1)/PAGESIZE)

// To obtain a pointer to the page containing the given linear address
#define PPAGEFROMP(p)           ((PVOID)((ULONG)(p) & ~(PAGESIZE-1)))
#define PPAGEFROMPGNO(p)        ((PVOID)((ULONG)(p) * PAGESIZE))
#define PGNOFROMP(p)            ((ULONG)(p) / PAGESIZE)


// To create a usable FAR pointer from an unusable FAR16 pointer
#define FPFROMF16P(fp,f16p)     OFFSETOF32(fp) = OFFSETOF16(f16p),\
                                SEGMENTOF32(fp) = SEGMENTOF16(f16p)

// To create pointers from V86-mode segments+offsets
// Note the validity of these pointers depends on the context they're used in
#define PFROMVP(vp)             ((PVOID)((WORDOF(vp,1)<<4)+WORDOF(vp,0)))
#define PFROMVADDR(seg,off)     ((PVOID)(((WORD)(seg)<<4)+(WORD)(off)))
#define VPFROMVADDR(seg,off)    ((VPVOID)(((WORD)(seg)<<16)|(WORD)(off)))

// To create V86 pointers from normal (flat) pointers
#define HISEG(p)                ((USHORT)((ULONG)(p)>>4))
#define LOOFF(p)                ((USHORT)((ULONG)(p)&0xf))
#define VPFROMP(p)              ((VPVOID)((((ULONG)(p)&~0xf)<<12)|((ULONG)(p)&0xf)))

#define LOSEG(p)                (((ULONG)(p)-HIOFF(p))>>4)
#define HIOFF(p)                (min(0xfff0,(ULONG)(p)&0xffff0)|((ULONG)(p)&0xf))
#define LOSEGVPFROMP(p)         ((VPVOID)((LOSEG(p)<<16)|HIOFF(p)))


// To calculate the byte offset of a field in a structure of type "type"
#define FIELDOFFSET(type,field) ((ULONG)&(((type *)0)->field))


// To extract high and low order parts of a 32-bit quantity
#define LOUSHORT(l)             (((PUSHORT)&(l))[0])
#define HIUSHORT(l)             (((PUSHORT)&(l))[1])

// To create pointer from V86-mode segment+offset
#define SEGOFF2P(seg,off)       ((PVOID)((seg<<4)+(USHORT)off))


/*** OS/2-specific macros
 */

#ifdef  INCL_SSTODS

#define SSToDS(p)       ((void *) (_TKSSBase + (unsigned) (p)))

extern char *_TKSSBase;

#endif
