/* 
WINCLIP.C -- Windows Clipboard access -- implementation 
386|DOS Extender functions for Windows 3.x (Enhanced) 
Clipboard 
*/ 
 
#include <stdlib.h> 
#include <stdio.h> 
#include <malloc.h> 
#include <string.h> 
#include <dos.h> 
#include <pharlap.h>
#include "winclip.h" 
 
static int clip_open=0; 
static int do_convert=1; 
 
/**************************************************************/ 
 
int PutClipStrLen(char *s, unsigned len) 
{ 
    int maj, min; 
    int ret = 0; 
    char *buf, *s2; 
    unsigned len2; 
     
    if (! WinOldApVersion(&maj, &min)) 
        return  1;  // Windows Enhanced mode isn't running 
 
    // change all 0d 0a to 0a 
    if (do_convert) 
    { 
        if ((buf = calloc(len, 1)) == NULL) 
            return 0;   // insufficient memory 
        for (s2=buf, len2=len; len2--; s2++, s++) 
        { 
            if ((s[0] == 0x0d) && (s[1] == 0x0a)) 
            { 
                s++; 
                len--;      // remove 0d 
            } 
            *s2 = *s; 
        } 
    } 
    else 
        buf=s; 
         
    if (! OpenClipboard()) 
        return 0; 
    clip_open++; 
    /* note: if calling program dies between OpenClipboard and 
       CloseClipboard, then no other program can access it until 
       Windows has been restarted. Perhaps put CloseClipboard() 
       call into ctrl-c handler */ 
    EmptyClipboard(); 
    if (CompactClipboard(len) < len) 
        puts("couldn't compact clipboard"); 
    else 
        ret = SetClipboardData(buf, CF_TEXT, len); 
    CloseClipboard(); 
    clip_open--; 
    free(buf); 
    return ret? 1 : 0; 
} 
 
int PutClipString(char *s) 
{ 
    return PutClipStrLen(s, strlen(s)+1); 
} 
 
char *GetClipString(void) 
{ 
    char *s; 
    REALPTR RealBufp;
    int maj, min; 
    unsigned long len; 
     
    if (! WinOldApVersion(&maj, &min)) 
        return 0; 
    if (! OpenClipboard()) 
        return (char *)0; 
    if ((len = GetClipboardSize(CF_TEXT)) == 0) 
    { 
        CloseClipboard(); 
        return NULL; 
    } 
    if ((s = malloc(len+1)) == NULL) // add one for ASCIIZ 
        return NULL; 
    RealBufp = GetClipboardData(CF_TEXT); 
    if (RealBufp == 0)
    {
        free(s);
	return NULL;
    }
    ReadRealMem(s, RealBufp, len);
    CloseClipboard();                   // important!! 
    FreeClipboardData(RealBufp);        // in conv mem buffer 
    s[len] = '\0';                      // make ASCIIZ 
    return s; 
} 
 
void FreeClipString(char *s) 
{ 
    free(s); 
} 
 
/**************************************************************/ 
 
/* INT 2Fh old application clipboard functions */ 
#define MPLEX           0x2f 
#define OPEN_CLIP       0x1701 
#define EMPTY_CLIP      0x1702 
#define SET_CLIP_DATA   0x1703 
#define GET_CLIP_SIZE   0x1704 
#define GET_CLIP_DATA   0x1705 
#define CLOSE_CLIP      0x1708 
#define CLIP_COMPACT    0x1709 
#define GET_DEV_CAPS    0x170A 
 
#define MAKEULONG(a, b)  ((((ULONG) (a)) & 0xFFFF) | (((ULONG) (b)) << 16))
 
#define LO(x)           ((x) & 0xFF) 
#define HI(x)           ((x) >> 8) 
#define CLEAR(x)        memset(&x, 0, sizeof(x)) 
 
int WinOldApVersion(int *maj, int *min) 
{ 
    CONFIG_INF config;
    UCHAR buf[256];

    _dx_config_inf(&config, buf);
    if (!config.c_windowsf || !config.c_winenhf)
    	return FALSE;
    else
    {
        *maj = config.c_winmaj;
	*min = config.c_winmin;
	return TRUE;
    }
} 
 
int OpenClipboard(void) 
{ 
    SWI_REGS r;
    CLEAR(r); 
    r.eax = OPEN_CLIP;
    _dx_real_int(MPLEX, &r);
    return r.eax;
} 
 
void EmptyClipboard(void) 
{ 
    SWI_REGS r; 
    CLEAR(r); 
    r.eax = EMPTY_CLIP; 
    _dx_real_int(MPLEX, &r);
} 
 
int SetClipboardData(void *data, CF_FORMAT format, unsigned long size) 
{ 
    SWI_REGS r; 
    USHORT addr; 
    USHORT largest;
    REALPTR RealBufp;
     
    CLEAR(r); 
 
    // allocate conventional memory, keep real mode seg addr 
    if (_dx_real_alloc(1 + (size >> 4), &addr, &largest) != 0)
        return 0; 
     
    // poke data into conv. mem. buffer using real mode selector 
    RP_SET(RealBufp, 0, addr);
    WriteRealMem(RealBufp, data, size);
     
    // pass the real mode address to the SET_CLIP_DATA function 
    r.es = addr; 
    r.ebx = 0; 
    r.eax = SET_CLIP_DATA; 
    r.edx = format; 
    r.esi = size >> 16; 
    r.ecx = size & 0xFFFF; 
 
    _dx_real_int(MPLEX, &r);
    _dx_real_free(addr);
    return (r.eax != 0); 
} 
 
unsigned long GetClipboardSize(CF_FORMAT format) 
{ 
    SWI_REGS r; 
    CLEAR(r); 
    r.eax = GET_CLIP_SIZE; 
    r.edx = format; 
    _dx_real_int(MPLEX, &r);
    return MAKEULONG(r.eax, r.edx); 
} 
 
REALPTR GetClipboardData(CF_FORMAT format) 
{ 
    SWI_REGS r; 
    unsigned long size; 
    USHORT addr; 
    USHORT largest;
    REALPTR RealBufp;
     
    CLEAR(r); 
     
    size = GetClipboardSize(format); 
 
    // allocate conv. memory, keep real mode segment address 
    if (_dx_real_alloc(1 + (size >> 4), &addr, &largest) != 0)
        return 0; 
     
    // pass the real mode address to the GET_CLIP_DATA function 
    r.es = addr; 
    r.ebx = 0; 
    r.eax = GET_CLIP_DATA; 
    r.edx = format; 
    _dx_real_int(MPLEX, &r);
 
    // return real mode FAR ptr to conventional memory buffer 
    RP_SET(RealBufp, 0, addr);
    return RealBufp; 
} 
 
void FreeClipboardData(REALPTR RealBufp)
{ 
    _dx_real_free(RP_SEG(RealBufp));
} 
 
void CloseClipboard(void) 
{ 
    SWI_REGS r; 
    CLEAR(r); 
    r.eax = CLOSE_CLIP; 
    _dx_real_int(MPLEX, &r);
} 
 
unsigned long CompactClipboard(unsigned long desire) 
{ 
    SWI_REGS r; 
    CLEAR(r); 
    r.eax = CLIP_COMPACT; 
    r.esi = desire >> 16; 
    r.ecx = desire & 0xFFFF; 
    _dx_real_int(MPLEX, &r);
    return MAKEULONG(r.eax, r.edx); 
} 
 
unsigned GetDeviceCaps(unsigned cap) 
{ 
    SWI_REGS r; 
    CLEAR(r); 
    r.eax = GET_DEV_CAPS; 
    r.edx = cap; 
    _dx_real_int(MPLEX, &r);
    return r.eax; 
} 
