/*
 * The C RunTime DLL
 * 
 * Implements C run-time functionality as known from UNIX.
 *
 * Copyright 1996 Marcus Meissner
 * Copyright 1996 Jukka Iivonen
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <ctype.h>
#include <math.h>
#include "win.h"
#include "windows.h"
#include "stddebug.h"
#include "debug.h"
#include "module.h"
#include "xmalloc.h"
#include "heap.h"
#include "crtdll.h"
#include "drive.h"
#include "file.h"

extern INT32 WIN32_wsprintf32W( int *args ) ;

UINT32 CRTDLL_argc_dll;         /* CRTDLL.23 */
LPSTR *CRTDLL_argv_dll;         /* CRTDLL.24 */
LPSTR  CRTDLL_acmdln_dll;       /* CRTDLL.38 */
UINT32 CRTDLL_basemajor_dll;    /* CRTDLL.42 */
UINT32 CRTDLL_baseminor_dll;    /* CRTDLL.43 */
UINT32 CRTDLL_baseversion_dll;  /* CRTDLL.44 */
LPSTR  CRTDLL_environ_dll;      /* CRTDLL.75 */
UINT32 CRTDLL_osmajor_dll;      /* CRTDLL.241 */
UINT32 CRTDLL_osminor_dll;      /* CRTDLL.242 */
UINT32 CRTDLL_osver_dll;        /* CRTDLL.244 */
UINT32 CRTDLL_osversion_dll;    /* CRTDLL.245 */
UINT32 CRTDLL_winmajor_dll;     /* CRTDLL.329 */
UINT32 CRTDLL_winminor_dll;     /* CRTDLL.330 */
UINT32 CRTDLL_winver_dll;       /* CRTDLL.331 */

typedef VOID (*new_handler_type)(VOID);

static new_handler_type new_handler;

/*********************************************************************
 *                  _GetMainArgs  (CRTDLL.022)
 */
DWORD
CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv,LPSTR *environ,DWORD flag)
{
        char *cmdline;
        char  **xargv;
	int	xargc,i,afterlastspace;
	DWORD	version;

	dprintf_crtdll(stderr,"CRTDLL__GetMainArgs(%p,%p,%p,%ld).\n",
		argc,argv,environ,flag
	);
	CRTDLL_acmdln_dll = cmdline = xstrdup( GetCommandLine32A() );

	version	= GetVersion32();
	CRTDLL_osver_dll       = version >> 16;
	CRTDLL_winminor_dll    = version & 0xFF;
	CRTDLL_winmajor_dll    = (version>>8) & 0xFF;
	CRTDLL_baseversion_dll = version >> 16;
	CRTDLL_winver_dll      = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8);
	CRTDLL_baseminor_dll   = (version >> 16) & 0xFF;
	CRTDLL_basemajor_dll   = (version >> 24) & 0xFF;
	CRTDLL_osversion_dll   = version & 0xFFFF;
	CRTDLL_osminor_dll     = version & 0xFF;
	CRTDLL_osmajor_dll     = (version>>8) & 0xFF;

	/* missing threading init */

	i=0;xargv=NULL;xargc=0;afterlastspace=0;
	while (cmdline[i]) {
		if (cmdline[i]==' ') {
			xargv=(char**)xrealloc(xargv,sizeof(char*)*(++xargc));
			cmdline[i]='\0';
			xargv[xargc-1] = xstrdup(cmdline+afterlastspace);
			i++;
			while (cmdline[i]==' ')
				i++;
			if (cmdline[i])
				afterlastspace=i;
		} else
			i++;
	}
	xargv=(char**)xrealloc(xargv,sizeof(char*)*(++xargc));
	cmdline[i]='\0';
	xargv[xargc-1] = xstrdup(cmdline+afterlastspace);
	CRTDLL_argc_dll	= xargc;
	*argc		= xargc;
	CRTDLL_argv_dll	= xargv;
	*argv		= xargv;

	/* FIXME ... use real environment */
	*environ	= xmalloc(sizeof(LPSTR));
	CRTDLL_environ_dll = *environ;
	(*environ)[0] = NULL;
	return 0;
}


typedef void (*_INITTERMFUN)();

/*********************************************************************
 *                  _initterm     (CRTDLL.135)
 */
DWORD CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end)
{
	_INITTERMFUN	*current;

	dprintf_crtdll(stddeb,"_initterm(%p,%p)\n",start,end);
	current=start;
	while (current<end) {
		if (*current) (*current)();
		current++;
	}
	return 0;
}

/*********************************************************************
 *                  fdopen     (CRTDLL.91)
 */
DWORD CRTDLL_fdopen(INT32 handle, LPCSTR mode)
{
  FILE *file;

  switch (handle) 
    {
    case 0 : file=stdin;
      break;
    case 1 : file=stdout;
      break;
    case 2 : file=stderr;
      break;
    default:
      file=fdopen(handle,mode);
    }
  dprintf_crtdll(stddeb,
		 "CRTDLL_fdopen open handle %d mode %s  got file %p\n",
		 handle, mode, file);
  return (DWORD)file;
}

/*********************************************************************
 *                  _fopen     (CRTDLL.372)
 */
DWORD CRTDLL_fopen(LPCSTR path, LPCSTR mode)
{
  FILE *file;
  DOS_FULL_NAME full_name;
  
  if (!DOSFS_GetFullName( path, FALSE, &full_name )) {
    dprintf_crtdll(stddeb,"CRTDLL_fopen file %s bad name\n",path);
   return 0;
  }
  
  file=fopen(full_name.long_name ,mode);
  dprintf_crtdll(stddeb,
		 "CRTDLL_fopen file %s (unix %s) mode %s  got file %p\n",
		 path, full_name.long_name, mode, file);
  return (DWORD)file;
}

/*********************************************************************
 *                  fread     (CRTDLL.377)
 */
DWORD CRTDLL_fread(LPVOID ptr, INT32 size, INT32 nmemb, LPVOID file)
{
  size_t ret;
  ret=fread(ptr,size,nmemb,file);
  dprintf_crtdll(stddeb,
		 "CRTDLL_fread 0x%x8x items of size %d from file %p to %p%s\n",
		 nmemb,size,ptr,file,(ret!=nmemb)?" failed":"");

  return ret;
}
  
/*********************************************************************
 *                  _fseek     (CRTDLL.382)
 */
LONG CRTDLL_fseek(LPVOID stream, LONG offset, INT32 whence)
{
  long ret;

  ret=fseek(stream,offset,whence);
  dprintf_crtdll(stddeb,
		 "CRTDLL_fseek file %p to 0x%08lx pos %s%s\n",
		 stream,offset,(whence==SEEK_SET)?"SEEK_SET":
		 (whence==SEEK_CUR)?"SEEK_CUR":
		 (whence==SEEK_END)?"SEEK_END":"UNKNOWN",
		 (ret)?"failed":"");
  return ret;
}
  
/*********************************************************************
 *                  _ftell     (CRTDLL.384)
 */
LONG CRTDLL_ftell(LPVOID stream)
{
  long ret;

  ret=ftell(stream);
  dprintf_crtdll(stddeb,
		 "CRTDLL_ftell file %p at 0x%08lx\n",
		 stream,ret);
  return ret;
}
  
/*********************************************************************
 *                  _fwrite     (CRTDLL.386)
 */
DWORD CRTDLL_fwrite(LPVOID ptr, INT32 size, INT32 nmemb, LPVOID file)
{
  size_t ret;

  ret=fwrite(ptr,size,nmemb,file);
  dprintf_crtdll(stddeb,
		 "CRTDLL_fwrite 0x%-8x items of size %d from %p to file %p%s\n",
		 nmemb,size,ptr,file,(ret!=nmemb)?" failed":"");
  return ret;
}
  
/*********************************************************************
 *                  setbuf     (CRTDLL.452)
 */
INT32 CRTDLL_setbuf(LPVOID file, LPSTR buf)
{
  dprintf_crtdll(stddeb,
		 "CRTDLL_setbuf(file %p buf %p)\n",
		 file,buf);

  setbuf(file,buf);
  return 0;
}

/*********************************************************************
 *                  _open_osfhandle         (CRTDLL.240)
 */
INT32 CRTDLL_open_osfhandle(LONG osfhandle, INT32 flags)
{
int file = 0; 
	switch (osfhandle) {
	case STD_INPUT_HANDLE :
	  file = 0;
	  break;
 	case STD_OUTPUT_HANDLE:
	  file = 1;
	  break;
	case STD_ERROR_HANDLE:
	  file = 2;
	  break;
	default:
	  return (-1);
	}
	dprintf_crtdll(stddeb,
		       "CRTDLL_open_osfhandle(handle %08lx,flags %d) return %d\n",
		       osfhandle,flags,file);
	return (INT32)file;
	
}

/*********************************************************************
 *                  srand         (CRTDLL.460)
 */
void CRTDLL_srand(DWORD seed)
{
	/* FIXME: should of course be thread? process? local */
	srand(seed);
}

/*********************************************************************
 *                  fprintf       (CRTDLL.373)
 */
int CRTDLL_fprintf(DWORD *args)
{
     int size=40; 
     char buf[size];
  
     vsnprintf(buf,size,(LPCSTR)(args[1]),(LPVOID)(args+2));
     dprintf_crtdll(stddeb,"CRTDLL_fprintf %s to file %p\n",
		    buf,(LPVOID)args[0]);
     return vfprintf((LPVOID)args[0],(LPCSTR)(args[1]),(LPVOID)(args+2));
}

/*********************************************************************
 *                  printf        (CRTDLL.440)
 */
int CRTDLL_printf(DWORD *args)
{
	return vfprintf(stdout,(LPSTR)(args[0]),args+1);
}

/*********************************************************************
 *                  sprintf        (CRTDLL.458)
 */
int CRTDLL_sprintf(DWORD *args)
{
     int size=40;
     char buf[size];
  
     vsnprintf(buf,size,(LPSTR)(args[1]),args+2);
     dprintf_crtdll(stddeb,"CRTDLL_sprintf %s\n",buf);
     return vsprintf((LPSTR)(args[0]),(LPSTR)(args[1]),args+2);
}

/*********************************************************************
 *                  vfprintf        (CRTDLL.497)
 */
int CRTDLL_vfprintf(DWORD *args)
{
     int size=40; 
     char buf[size];

     vsnprintf(buf,size,(LPCSTR)(args[1]),(LPVOID)(args[2]));
     dprintf_crtdll(stddeb,"CRTDLL_vfprintf %s to file%p",buf,(LPVOID)args[0]);
     return vfprintf((LPVOID)args[0],(LPSTR)(args[1]),(LPVOID)args[2]);
}

/*********************************************************************
 *                  time          (CRTDLL.488)
 */
time_t CRTDLL_time(time_t *timeptr)
{
	time_t	curtime = time(NULL);

	if (timeptr)
		*timeptr = curtime;
	return curtime;
}

/*********************************************************************
 *                  _isatty       (CRTDLL.137)
 */
BOOL32 CRTDLL__isatty(DWORD x)
{
	dprintf_crtdll(stderr,"CRTDLL__isatty(%ld)\n",x);
	return TRUE;
}

/*********************************************************************
 *                  _write        (CRTDLL.332)
 */
INT32 CRTDLL_write(INT32 x,LPCVOID buf,DWORD len)
{
	dprintf_crtdll(stddeb,"CRTDLL_write %ld byte to fh %d from %p,\n",
		       len,x,buf);
	if (x<=2)
		return write(x,buf,len);
	/* hmm ... */
	return len;
}


/*********************************************************************
 *                  _cexit          (CRTDLL.49)
 *
 *  FIXME: What the heck is the difference between 
 *  FIXME           _c_exit         (CRTDLL.47)
 *  FIXME           _cexit          (CRTDLL.49)
 *  FIXME           _exit           (CRTDLL.87)
 *  FIXME           exit            (CRTDLL.359)
 *
 */
void CRTDLL__cexit(INT32 ret)
{
        dprintf_crtdll(stderr,"CRTDLL__cexit(%d)\n",*(int *)ret);
	ExitProcess(ret);
}


/*********************************************************************
 *                  exit          (CRTDLL.359)
 */
void CRTDLL_exit(DWORD ret)
{
        dprintf_crtdll(stderr,"CRTDLL_exit(%ld)\n",ret);
	ExitProcess(ret);
}


/*********************************************************************
 *                  fflush        (CRTDLL.365)
 */
void CRTDLL_fflush(DWORD x)
{
    dprintf_crtdll(stderr,"CRTDLL_fflush(%ld)\n",x);
}


/*********************************************************************
 *                  gets          (CRTDLL.391)
 */
LPSTR CRTDLL_gets(LPSTR buf)
{
  /* BAD, for the whole WINE process blocks... just done this way to test
   * windows95's ftp.exe.
   */
    return gets(buf);
}


/*********************************************************************
 *                  abs           (CRTDLL.339)
 */
INT32 CRTDLL_abs(INT32 x)
{
    return abs(x);
}


/*********************************************************************
 *                  acos          (CRTDLL.340)
 */
float CRTDLL_acos(float x)
{
    return acos(x);
}


/*********************************************************************
 *                  asin          (CRTDLL.342)
 */
float CRTDLL_asin(float x)
{
    return asin(x);
}


/*********************************************************************
 *                  atan          (CRTDLL.343)
 */
float CRTDLL_atan(float x)
{
    return atan(x);
}


/*********************************************************************
 *                  atan2         (CRTDLL.344)
 */
float CRTDLL_atan2(float x, float y)
{
    return atan2(x,y);
}


/*********************************************************************
 *                  atof          (CRTDLL.346)
 */
float CRTDLL_atof(LPCSTR x)
{
    return atof(x);
}


/*********************************************************************
 *                  atoi          (CRTDLL.347)
 */
INT32 CRTDLL_atoi(LPCSTR x)
{
    return atoi(x);
}


/*********************************************************************
 *                  itoa          (CRTDLL.165)
 */
CHAR* CRTDLL_itoa(INT32 x,LPSTR buf,INT32 len)
{
   if ( snprintf(buf,len,"%d",x) > len) {
    dprintf_crtdll(stddeb,
      "CRTDLL_itoa failed\n");
        return NULL;
   }
   dprintf_crtdll(stddeb,
		  "CRTDLL_itoa  %d to %s at %p len %d\n",x,buf,buf,len);
   return buf;
    
}


/*********************************************************************
 *                  lrotl          (CRTDLL.176)
 */
DWORD CRTDLL_lrotl(DWORD x,INT32 shift)
{
   unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift));

   dprintf_crtdll(stddeb,
		  "CRTDLL_lrotl got 0x%08lx rot %d ret 0x%08lx\n",
		  x,shift,ret);
   return ret;
    
}


/*********************************************************************
 *                  atol          (CRTDLL.348)
 */
LONG CRTDLL_atol(LPCSTR x)
{
    return atol(x);
}


/*********************************************************************
 *                  cos           (CRTDLL.354)
 */
float CRTDLL_cos(float x)
{
    return cos(x);
}


/*********************************************************************
 *                  cosh          (CRTDLL.355)
 */
float CRTDLL_cosh(float x)
{
    return cosh(x);
}


/*********************************************************************
 *                  exp           (CRTDLL.360)
 */
float CRTDLL_exp(float x)
{
    return exp(x);
}


/*********************************************************************
 *                  fabs          (CRTDLL.361)
 */
float CRTDLL_fabs(float x)
{
    return fabs(x);
}


/*********************************************************************
 *                  isalnum       (CRTDLL.394)
 */
CHAR CRTDLL_isalnum(CHAR x)
{
    return isalnum(x);
}


/*********************************************************************
 *                  isalpha       (CRTDLL.395)
 */
CHAR CRTDLL_isalpha(CHAR x)
{
    return isalpha(x);
}


/*********************************************************************
 *                  iscntrl       (CRTDLL.396)
 */
CHAR CRTDLL_iscntrl(CHAR x)
{
    return iscntrl(x);
}


/*********************************************************************
 *                  isdigit       (CRTDLL.397)
 */
CHAR CRTDLL_isdigit(CHAR x)
{
    return isdigit(x);
}


/*********************************************************************
 *                  isgraph       (CRTDLL.398)
 */
CHAR CRTDLL_isgraph(CHAR x)
{
    return isgraph(x);
}


/*********************************************************************
 *                  islower       (CRTDLL.400)
 */
CHAR CRTDLL_islower(CHAR x)
{
    return islower(x);
}


/*********************************************************************
 *                  isprint       (CRTDLL.401)
 */
CHAR CRTDLL_isprint(CHAR x)
{
    return isprint(x);
}


/*********************************************************************
 *                  ispunct       (CRTDLL.402)
 */
CHAR CRTDLL_ispunct(CHAR x)
{
    return ispunct(x);
}


/*********************************************************************
 *                  isspace       (CRTDLL.403)
 */
CHAR CRTDLL_isspace(CHAR x)
{
    return isspace(x);
}


/*********************************************************************
 *                  isupper       (CRTDLL.404)
 */
CHAR CRTDLL_isupper(CHAR x)
{
    return isupper(x);
}


/*********************************************************************
 *                  isxdigit      (CRTDLL.418)
 */
CHAR CRTDLL_isxdigit(CHAR x)
{
    return isxdigit(x);
}


/*********************************************************************
 *                  labs          (CRTDLL.419)
 */
LONG CRTDLL_labs(LONG x)
{
    return labs(x);
}


/*********************************************************************
 *                  log           (CRTDLL.424)
 */
float CRTDLL_log(float x)
{
    return log(x);
}


/*********************************************************************
 *                  log10         (CRTDLL.425)
 */
float CRTDLL_log10(float x)
{
    return log10(x);
}


/*********************************************************************
 *                  pow           (CRTDLL.439)
 */
float CRTDLL_pow(float x, float y)
{
    return pow(x,y);
}


/*********************************************************************
 *                  rand          (CRTDLL.446)
 */
INT32 CRTDLL_rand()
{
    return rand();
}


/*********************************************************************
 *                  sin           (CRTDLL.456)
 */
float CRTDLL_sin(float x)
{
    return sin(x);
}


/*********************************************************************
 *                  sinh          (CRTDLL.457)
 */
float CRTDLL_sinh(float x)
{
    return sinh(x);
}


/*********************************************************************
 *                  sqrt          (CRTDLL.459)
 */
float CRTDLL_sqrt(float x)
{
    return sqrt(x);
}


/*********************************************************************
 *                  tan           (CRTDLL.486)
 */
float CRTDLL_tan(float x)
{
    return tan(x);
}


/*********************************************************************
 *                  tanh          (CRTDLL.487)
 */
float CRTDLL_tanh(float x)
{
    return tanh(x);
}


/*********************************************************************
 *                  tolower       (CRTDLL.491)
 */
CHAR CRTDLL_tolower(CHAR x)
{
    return tolower(x);
}


/*********************************************************************
 *                  toupper       (CRTDLL.492)
 */
CHAR CRTDLL_toupper(CHAR x)
{
    return toupper(x);
}


/*********************************************************************
 *                  putchar       (CRTDLL.442)
 */
void CRTDLL_putchar(INT32 x)
{
    putchar(x);
}


/*********************************************************************
 *                  fputc       (CRTDLL.374)
 */
INT32 CRTDLL_fputc(INT32 c,LPVOID stream)
{
  dprintf_crtdll(stddeb,
		 "CRTDLL_fputc %c to file %p\n",c,stream);
    return fputc(c,stream);
}


/*********************************************************************
 *                  fputs       (CRTDLL.375)
 */
INT32 CRTDLL_fputs(LPCSTR s,LPVOID stream)
{
  dprintf_crtdll(stddeb,
		 "CRTDLL_fputs %s to file %p\n",s,stream);
    return fputs(s,stream);
}


/*********************************************************************
 *                  putc       (CRTDLL.441)
 */
INT32 CRTDLL_putc(INT32 c,LPVOID stream)
{
  dprintf_crtdll(stddeb,
		 "CRTDLL_putc %c to file %p\n",c,stream);
    return fputc(c,stream);
}


/*********************************************************************
 *                  fgets       (CRTDLL.368)
 */
CHAR* CRTDLL_fgets(LPSTR s,INT32 size, LPVOID stream)
{
  char * ret;
  char * control_M;
  
  ret=fgets(s, size,stream);
  /*FIXME: Control with CRTDLL_setmode */
  control_M= strrchr(s,'\r');
  /*delete CR if we read a DOS File */
  if (control_M)
    {
      *control_M='\n';
      *(control_M+1)=0;
    }
  dprintf_crtdll(stddeb,
		 "CRTDLL_fgets got %s for %d chars from file %p%s\n",
		 s,size,stream,(ret)?"":" failed");
  return ret;
}


/*********************************************************************
 *                  fgetc       (CRTDLL.366)
 */
INT32 CRTDLL_fgetc(LPVOID stream)
{
  int ret= fgetc(stream);
  dprintf_crtdll(stddeb,
		 "CRTDLL_fgetc got %d\n",ret);
  return ret;
}


/*********************************************************************
 *                  getc       (CRTDLL.388)
 */
INT32 CRTDLL_getc(LPVOID stream)
{
  int ret= fgetc(stream);
  dprintf_crtdll(stddeb,
		 "CRTDLL_getc got %d\n",ret);
  return ret;
}


/*********************************************************************
 *                  _mbsicmp      (CRTDLL.204)
 */
int CRTDLL__mbsicmp(unsigned char *x,unsigned char *y)
{
    do {
	if (!*x)
	    return !!*y;
	if (!*y)
	    return !!*x;
	/* FIXME: MBCS handling... */
	if (*x!=*y)
	    return 1;
        x++;
        y++;
    } while (1);
}


/*********************************************************************
 *                  _mbsinc       (CRTDLL.205)
 */
unsigned char* CRTDLL__mbsinc(unsigned char *x)
{
    /* FIXME: mbcs */
    return x++;
}


/*********************************************************************
 *                  vsprintf      (CRTDLL.500)
 */
int CRTDLL_vsprintf(DWORD *args)
{
    int size=40; 
    char buf[size];

    vsnprintf(buf,size,(LPCSTR)(args[1]),(LPVOID)(args[2]));
    dprintf_crtdll(stddeb,"CRTDLL_vsprintf %s to buf %p",buf,(LPVOID)args[0]);
    vsnprintf(buf,size,(LPCSTR)(args[1]),(LPVOID)(args[2]));
    return vsprintf((char *)args[0],(char *)args[1],(LPVOID)args[2]);
}

/*********************************************************************
 *                  vsprintf      (CRTDLL.500) (NTDLL.913)
 */
int CRTDLL_sscanf(DWORD *args)
{
    return vsscanf((char *)args[0],(char *)args[1],args+2);
}


/*********************************************************************
 *                  _mbscpy       (CRTDLL.200)
 */
unsigned char* CRTDLL__mbscpy(unsigned char *x,unsigned char *y)
{
    dprintf_crtdll(stddeb,"CRTDLL_mbscpy %s and %s\n",x,y);
    return strcpy(x,y);
}


/*********************************************************************
 *                  _mbscat       (CRTDLL.197)
 */
unsigned char* CRTDLL__mbscat(unsigned char *x,unsigned char *y)
{
    return strcat(x,y);
}

/*********************************************************************
 *                  _strlwr      (CRTDLL.293)
 *
 * convert a string in place to lowercase 
 */
LPSTR CRTDLL_strlwr(LPSTR x)
{
  unsigned char *y =x;
  
  dprintf_crtdll(stddeb,
		 "CRTDLL_strlwr got %s",x);
  while (*y) {
    if ((*y > 0x40) && (*y< 0x5b))
      *y = *y + 0x20;
    y++;
  }
  dprintf_crtdll(stddeb," returned %s\n",x);
		 
  return x;
}

/*********************************************************************
 *                  system       (CRTDLL.485)
 */
INT32 CRTDLL_system(LPSTR x)
{
  char buffer[100]="wine \"";
  unsigned char *y =x;
  unsigned char *bp =buffer+strlen(buffer);

  while (*y) {
    *bp = *y;
    bp++; y++;
    if (*(y-1) =='\\') *bp++ = '\\';
  }
  *bp++ = '"';
  *bp++ = NULL;
  dprintf_crtdll(stddeb,
		 "_system got %s, executing %s\n",x,buffer);

  return system(buffer);;
}

/*********************************************************************
 *                  _strupr       (CRTDLL.300)
 */
LPSTR CRTDLL__strupr(LPSTR x)
{
	LPSTR	y=x;

	while (*y) {
		*y=toupper(*y);
		y++;
	}
	return x;
}

/*********************************************************************
 *                  _wcsupr       (CRTDLL.328)
 */
LPWSTR CRTDLL__wcsupr(LPWSTR x)
{
	LPWSTR	y=x;

	while (*y) {
		*y=toupper(*y);
		y++;
	}
	return x;
}

/*********************************************************************
 *                  _wcslwr       (CRTDLL.323)
 */
LPWSTR CRTDLL__wcslwr(LPWSTR x)
{
	LPWSTR	y=x;

	while (*y) {
		*y=tolower(*y);
		y++;
	}
	return x;
}


/*********************************************************************
 *                  malloc        (CRTDLL.427)
 */
VOID* CRTDLL_malloc(DWORD size)
{
    return HeapAlloc(GetProcessHeap(),0,size);
}

/*********************************************************************
 *                  new           (CRTDLL.001)
 */
VOID* CRTDLL_new(DWORD size)
{
    VOID* result;
    if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler)
	(*new_handler)();
    return result;
}

/*********************************************************************
 *                  set_new_handler(CRTDLL.003)
 */
new_handler_type CRTDLL_set_new_handler(new_handler_type func)
{
    new_handler_type old_handler = new_handler;
    new_handler = func;
    return old_handler;
}

/*********************************************************************
 *                  calloc        (CRTDLL.350)
 */
VOID* CRTDLL_calloc(DWORD size, DWORD count)
{
    return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count );
}

/*********************************************************************
 *                  realloc        (CRTDLL.447)
 */
VOID* CRTDLL_realloc( VOID *ptr, DWORD size )
{
    return HeapReAlloc( GetProcessHeap(), 0, ptr, size );
}

/*********************************************************************
 *                  free          (CRTDLL.427)
 */
VOID CRTDLL_free(LPVOID ptr)
{
    HeapFree(GetProcessHeap(),0,ptr);
}

/*********************************************************************
 *                  delete       (CRTDLL.002)
 */
VOID CRTDLL_delete(VOID* ptr)
{
    HeapFree(GetProcessHeap(),0,ptr);
}

/*********************************************************************
 *                  _strdup          (CRTDLL.285)
 */
LPSTR CRTDLL__strdup(LPSTR ptr)
{
    return HEAP_strdupA(GetProcessHeap(),0,ptr);
}

/*********************************************************************
 *                  fclose           (CRTDLL.362)
 */
INT32 CRTDLL_fclose(LPVOID stream)
{
    int ret=fclose(stream);

    dprintf_crtdll(stddeb,"CRTDLL_fclose(%p)%s\n",stream,(ret)?" failed":"");
    return ret;
}

/*********************************************************************
 *                  unlink           (CRTDLL.315)
 */
INT32 CRTDLL_unlink(LPCSTR pathname)
{
    int ret;
    DOS_FULL_NAME full_name;

    if (!DOSFS_GetFullName( pathname, FALSE, &full_name )) {
      dprintf_crtdll(stddeb,"CRTDLL_unlink file %s bad name\n",pathname);
      return EOF;
    }
  
    ret=unlink(full_name.long_name);
    dprintf_crtdll(stddeb,"CRTDLL_unlink(%s unix %s)%s\n",
		   pathname,full_name.long_name, (ret)?" failed":"");
    return ret;
}

/*********************************************************************
 *                  close           (CRTDLL.57)
 */
INT32 CRTDLL_close(INT32 fd)
{
    int ret=close(fd);

    dprintf_crtdll(stddeb,"fclose(%d)%s\n",fd,(ret)?" failed":"");
    return close(fd);
}

/*********************************************************************
 *                  feof           (CRTDLL.363)
 */
INT32 CRTDLL_feof(LPVOID stream)
{
    int ret;
    
    ret=feof(stream);
    dprintf_crtdll(stddeb,"CRTDLL_feof(%p) %s\n",stream,(ret)?"true":"false");
    return ret;
}

/*********************************************************************
 *                  setlocale           (CRTDLL.453)
 */
LPSTR CRTDLL_setlocale(INT32 category,LPCSTR locale)
{
	LPSTR categorystr;

	switch (category) {
	case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
	case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
	case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
	case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
	case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
	case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
	default: categorystr = "UNKNOWN?";break;
	}
	fprintf(stderr,"CRTDLL_setlocale(%s,%s),stub!\n",categorystr,locale);
	return "C";
}

/*********************************************************************
 *                  wcsspn           (CRTDLL.516)
 */
INT32 CRTDLL_wcsspn(LPWSTR str,LPWSTR accept)
{
	LPWSTR	s,t;

	s=str;
	do {
		t=accept;
		while (*t) { if (*t==*s) break;t++;}
		if (!*t) break;
		s++;
	} while (*s);
	return s-str; /* nr of wchars */
}

/*********************************************************************
 *                  wcscspn           (CRTDLL.508)
 */
INT32 CRTDLL_wcscspn(LPWSTR str,LPWSTR reject)
{
	LPWSTR	s,t;

	s=str;
	do {
		t=reject;
		while (*t) { if (*t==*s) break;t++;}
		if (*t) break;
		s++;
	} while (*s);
	return s-str; /* nr of wchars */
}

/*********************************************************************
 *                  wcschr           (CRTDLL.504)
 */
LPWSTR CRTDLL_wcschr(LPWSTR str,WCHAR xchar)
{
	LPWSTR	s;

	s=str;
	do {
		if (*s==xchar)
			return s;
	} while (*s++);
	return NULL;
}

/*********************************************************************
 *                  towupper           (CRTDLL.494)
 */
WCHAR CRTDLL_towupper(WCHAR x)
{
    return (WCHAR)toupper((CHAR)x);
}

/*********************************************************************
 *                  swprintf           (CRTDLL.483)
 */
DWORD CRTDLL_swprintf(DWORD *args)
{
    return WIN32_wsprintf32W((int*)args);
}

/*********************************************************************
 *                  _wcsicoll           (CRTDLL.322)
 */
DWORD CRTDLL__wcsicoll(LPWSTR a1,LPWSTR a2)
{
    /* FIXME: handle collates */
    return lstrcmpi32W(a1,a2);
}

/*********************************************************************
 *                  wcscoll           (CRTDLL.506)
 */
DWORD CRTDLL_wcscoll(LPWSTR a1,LPWSTR a2)
{
    /* FIXME: handle collates */
    return lstrcmp32W(a1,a2);
}

/*********************************************************************
 *                  _wcsrev           (CRTDLL.326)
 */
VOID CRTDLL__wcsrev(LPWSTR s) {
	LPWSTR	e;

	e=s;
	while (*e)
		e++;
	while (s<e) {
		WCHAR	a;

		a=*s;*s=*e;*e=a;
		s++;e--;
	}
}

/*********************************************************************
 *                  wcsstr           (CRTDLL.517)
 */
LPWSTR CRTDLL_wcsstr(LPWSTR s,LPWSTR b)
{
	LPWSTR	x,y,c;

	x=s;
	while (*x) {
		if (*x==*b) {
			y=x;c=b;
			while (*y && *c && *y==*c) { c++;y++; }
			if (!*c)
				return x;
		}
		x++;
	}
	return NULL;
}

/*********************************************************************
 *                  wcsrchr           (CRTDLL.515)
 */
LPWSTR CRTDLL_wcsrchr(LPWSTR str,WCHAR xchar)
{
	LPWSTR	s;

	s=str+lstrlen32W(str);
	do {
		if (*s==xchar)
			return s;
		s--;
	} while (s>=str);
	return NULL;
}

/*********************************************************************
 *                  _setmode           (CRTDLL.265)
 * FIXME: dunno what this is.
 */
INT32 
CRTDLL__setmode( INT32 fh,INT32 mode) {
	/* FIXME */
#define O_TEXT     0x4000
#define O_BINARY   0x8000

	fprintf(stdnimp,"CRTDLL._setmode on fhandle %d mode %s, STUB.\n",
		fh,(mode=O_TEXT)?"O_TEXT":
		(mode=O_BINARY)?"O_BINARY":"UNKNOWN");
	return -1;
}

/*********************************************************************
 *                  atexit           (CRTDLL.345)
 */
INT32
CRTDLL_atexit(LPVOID x) {
	/* FIXME */
	fprintf(stdnimp,"CRTDLL.atexit(%p), STUB.\n",x);
	return 0; /* successful */
}

/*********************************************************************
 *                  mblen          (CRTDLL.428)
 * FIXME: check multibyte support
 */
WCHAR
CRTDLL_mblen(CHAR *mb,INT32 size) {

    int ret=1;
    
    if (!mb)
      ret = 0;
    else if ((size<1)||(!*(mb+1)))
      ret = -1;
    else if (!(*mb))
      ret =0;
      
    dprintf_crtdll(stderr,"CRTDLL_mlen %s for max %d bytes ret %d\n",mb,size,ret);

    return ret;
}

/*********************************************************************
 *                  mbstowcs           (CRTDLL.429)
 * FIXME: check multibyte support
 */
INT32
CRTDLL_mbstowcs(LPWSTR wcs, LPCSTR mbs, INT32 size) {

/* Slightly modified lstrcpynAtoW functions from memory/strings.c
 *  We need the nimberr of characters transfered 
 *  FIXME: No multibyte support yet
 */

    LPWSTR p = wcs;
    LPCSTR src= mbs;
    int ret;

    dprintf_crtdll(stderr,"CRTDLL_mbstowcs %s for %d chars from %p to %p\n",
		   mbs,size,mbs,wcs);
    while ((size-- > 1) && *src) {
      *p++ = (WCHAR)(unsigned char)*src++;
      p++;
    }
    *p++ =0;
    ret = (p -wcs)/2;
          
    dprintf_crtdll(stderr,"CRTDLL_mbstowcs %s for %d chars put %d chars\n",
		   mbs,size,ret);
    return ret;
}

/*********************************************************************
 *                  mbtowc           (CRTDLL.430)
 * FIXME: check multibyte support
 */
WCHAR
CRTDLL_mbtowc(WCHAR* wc,CHAR* mb,INT32 size) 
{
   int ret;

   if (!mb)
     ret = 0;
   else if (!wc)
     ret =-1;
   else 
     if ( (ret = mblen(mb,size)) != -1 )
       {
	 if (ret <= sizeof(char))
	   *wc = (WCHAR) ((unsigned char)*mb);
        else
        ret=   -1;
        }   
     else
       ret = -1;
   
   dprintf_crtdll(stderr,"CRTDLL_mbtowc %s for %d chars\n",mb,size);
         
   return ret;
}

/*********************************************************************
 *                  _isctype           (CRTDLL.138)
 */
BOOL32
CRTDLL__isctype(CHAR x,CHAR type) {
	if ((type & CRTDLL_SPACE) && isspace(x))
		return TRUE;
	if ((type & CRTDLL_PUNCT) && ispunct(x))
		return TRUE;
	if ((type & CRTDLL_LOWER) && islower(x))
		return TRUE;
	if ((type & CRTDLL_UPPER) && isupper(x))
		return TRUE;
	if ((type & CRTDLL_ALPHA) && isalpha(x))
		return TRUE;
	if ((type & CRTDLL_DIGIT) && isdigit(x))
		return TRUE;
	if ((type & CRTDLL_CONTROL) && iscntrl(x))
		return TRUE;
	/* check CRTDLL_LEADBYTE */
	return FALSE;
}

/*********************************************************************
 *                  _chdrive           (CRTDLL.52)
 */
BOOL32
CRTDLL__chdrive(INT32 newdrive) {
	/* FIXME: generates errnos */
	return DRIVE_SetCurrentDrive(newdrive);
}

/*********************************************************************
 *                  _chdir           (CRTDLL.51)
 */
INT32
CRTDLL__chdir(LPCSTR newdir) {
	if (!SetCurrentDirectory32A(newdir))
		return -1;
	return 0;
}

/*********************************************************************
 *                  _getcwd           (CRTDLL.120)
 */
CHAR*
CRTDLL_getcwd(LPSTR buf, INT32 size)
{
  DOS_FULL_NAME full_name;
  char *ret;

  dprintf_crtdll(stddeb,"CRTDLL_getcwd for buf %p size %d\n",
		 buf,size);
  if (buf == NULL)
    {
      dprintf_crtdll(stderr,"CRTDLL_getcwd malloc unsupported\n");
      printf("CRTDLL_getcwd malloc unsupported\n");
      return 0;
    }
  ret = getcwd(buf,size);
  if (!DOSFS_GetFullName( buf, FALSE, &full_name )) 
    {
      dprintf_crtdll(stddeb,"CRTDLL_getcwd failed\n");
      return 0;
    }
  if (strlen(full_name.short_name)>size) 
    {
      dprintf_crtdll(stddeb,"CRTDLL_getcwd string too long\n");
      return 0;
    }
  ret=strcpy(buf,full_name.short_name);
  if (ret) 
    dprintf_crtdll(stddeb,"CRTDLL_getcwd returned:%s\n",ret);
  return ret;
}

/*********************************************************************
 *                  _mkdir           (CRTDLL.234)
 */
INT32
CRTDLL__mkdir(LPCSTR newdir) {
	if (!CreateDirectory32A(newdir,NULL))
		return -1;
	return 0;
}

/*********************************************************************
 *                  _errno           (CRTDLL.52)
 * Yes, this is a function.
 */
LPINT32
CRTDLL__errno() {
	static	int crtdllerrno;
	extern int LastErrorToErrno(DWORD);

	/* FIXME: we should set the error at the failing function call time */
	crtdllerrno = LastErrorToErrno(GetLastError());
	return &crtdllerrno;
}
/*********************************************************************
 *                  _tempname           (CRTDLL.305)
 * 
 */
LPSTR
CRTDLL_tempnam(LPCSTR dir, LPCSTR prefix) {

     char *ret;
     
     ret = tempnam(dir,prefix);
     dprintf_crtdll(stddeb,"CRTDLL_tempnam for dir %s prefix %s %s%s\n",
		    dir,prefix,(ret)?"got ":"failed",(ret)?ret:"");
     return ret;

}
/*********************************************************************
 *                  _tmpnam           (CRTDLL.490)
 * 
 */
LPSTR
CRTDLL_tmpnam(LPSTR s) {

     char *ret;
     
     ret = tmpnam(s);
     dprintf_crtdll(stddeb,"CRTDLL_tmpnam for buf %p got %s\n",
		    s,ret);
     return ret;

}
