scummvm/backends/platform/wince/missing/missing.cpp

365 lines
7.9 KiB
C++
Raw Normal View History

2001-11-18 10:24:36 +00:00
/* MISSING.C
Implementation for standard and semi-standard C library calls missing in WinCE
environment.
2002-07-19 21:39:41 +00:00
by Vasyl Tsvirkunov
2001-11-18 10:24:36 +00:00
*/
2002-07-19 21:39:41 +00:00
2001-11-18 10:24:36 +00:00
#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <stdlib.h>
2001-11-18 10:24:36 +00:00
#include "sys/stat.h"
#ifndef __GNUC__
2001-11-18 10:24:36 +00:00
#include "sys/time.h"
#else
#include <stdio.h>
#endif
2001-11-18 10:24:36 +00:00
#include "time.h"
#include "dirent.h"
/* forward declaration */
#if _WIN32_WCE < 300
#define _STDAFX_H
#include "portdefs.h"
#else
2001-11-18 10:24:36 +00:00
char *strdup(const char *strSource);
#endif
#ifdef __GNUC__
#define EXT_C extern "C"
#else
#define EXT_C
#endif
// common missing functions required by both gcc and evc
void *bsearch(const void *key, const void *base, size_t nmemb,
size_t size, int (*compar)(const void *, const void *)) {
// Perform binary search
size_t lo = 0;
size_t hi = nmemb;
while (lo < hi) {
size_t mid = (lo + hi) / 2;
const void *p = ((const char *)base) + mid * size;
int tmp = (*compar)(key, p);
if (tmp < 0)
hi = mid;
else if (tmp > 0)
lo = mid + 1;
else
return (void *)p;
}
return NULL;
}
2001-11-18 10:24:36 +00:00
static WIN32_FIND_DATA wfd;
/* Very limited implementation of stat. Used by UI.C, MEMORY-P.C (latter is not critical) */
int stat(const char *fname, struct stat *ss)
{
TCHAR fnameUnc[MAX_PATH+1];
HANDLE handle;
int len;
2007-09-18 20:16:33 +00:00
if (fname == NULL || ss == NULL)
return -1;
/* Special case (dummy on WinCE) */
len = strlen(fname);
2007-09-18 20:16:33 +00:00
if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' &&
(len == 2 || fname[len-3] == '\\'))
{
/* That's everything implemented so far */
memset(ss, 0, sizeof(struct stat));
ss->st_size = 1024;
ss->st_mode |= S_IFDIR;
return 0;
}
MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH);
handle = FindFirstFile(fnameUnc, &wfd);
FindClose(handle);
2007-09-18 20:16:33 +00:00
if (handle == INVALID_HANDLE_VALUE)
return -1;
else
{
/* That's everything implemented so far */
memset(ss, 0, sizeof(struct stat));
ss->st_size = wfd.nFileSizeLow;
2007-09-18 20:16:33 +00:00
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ss->st_mode |= S_IFDIR;
}
return 0;
}
char cwd[MAX_PATH+1] = "";
EXT_C char *getcwd(char *buffer, int maxlen)
{
TCHAR fileUnc[MAX_PATH+1];
char* plast;
2007-09-18 20:16:33 +00:00
if (cwd[0] == 0)
{
GetModuleFileName(NULL, fileUnc, MAX_PATH);
WideCharToMultiByte(CP_ACP, 0, fileUnc, -1, cwd, MAX_PATH, NULL, NULL);
plast = strrchr(cwd, '\\');
2007-09-18 20:16:33 +00:00
if (plast)
*plast = 0;
/* Special trick to keep start menu clean... */
2007-09-18 20:16:33 +00:00
if (_stricmp(cwd, "\\windows\\start menu") == 0)
strcpy(cwd, "\\Apps");
}
2007-09-18 20:16:33 +00:00
if (buffer)
strncpy(buffer, cwd, maxlen);
return cwd;
}
#ifdef __GNUC__
#undef GetCurrentDirectory
#endif
EXT_C void GetCurrentDirectory(int len, char *buf)
{
getcwd(buf,len);
};
/*
Windows CE fopen has non-standard behavior -- not
fully qualified paths refer to root folder rather
than current folder (concept not implemented in CE).
*/
#undef fopen
EXT_C FILE *wce_fopen(const char* fname, const char* fmode)
{
char fullname[MAX_PATH+1];
2007-09-18 20:16:33 +00:00
if (!fname || fname[0] == '\0')
return NULL;
2007-09-18 20:16:33 +00:00
if (fname[0] != '\\' && fname[0] != '/')
{
getcwd(fullname, MAX_PATH);
strncat(fullname, "\\", MAX_PATH-strlen(fullname)-1);
strncat(fullname, fname, MAX_PATH-strlen(fullname)-strlen(fname));
return fopen(fullname, fmode);
}
else
return fopen(fname, fmode);
}
/* Remove file by name */
int remove(const char* path)
{
TCHAR pathUnc[MAX_PATH+1];
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
return !DeleteFile(pathUnc);
}
/* check out file access permissions */
int _access(const char *path, int mode) {
TCHAR fname[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname)/sizeof(TCHAR));
WIN32_FIND_DATA ffd;
HANDLE h=FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) {
// WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry
// hits for files that don't exist. Checking for the same fname twice
// seems to weed out those false positives.
HANDLE h=FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
return 0; //Always return success if target is directory and exists
}
switch (mode) {
case 00: //Check existence
return 0;
case 06: //Check Read & Write permission
case 02: //Check Write permission
return ffd.dwFileAttributes&FILE_ATTRIBUTE_READONLY?-1:0;
case 04: //Check Read permission
return 0; //Assume always have read permission
}
//Bad mode value supplied, return failure
return -1;
}
// evc only functions follow
#ifndef __GNUC__
/* Limited dirent implementation. Used by UI.C and DEVICES.C */
2001-11-18 10:24:36 +00:00
DIR* opendir(const char* fname)
{
DIR* pdir;
char fnameMask[MAX_PATH+1];
TCHAR fnameUnc[MAX_PATH+1];
char nameFound[MAX_PATH+1];
2007-09-18 20:16:33 +00:00
if (fname == NULL)
2001-11-18 10:24:36 +00:00
return NULL;
2001-11-18 10:24:36 +00:00
strcpy(fnameMask, fname);
2007-09-18 20:16:33 +00:00
if (!strlen(fnameMask) || fnameMask[strlen(fnameMask)-1] != '\\')
2001-11-18 10:24:36 +00:00
strncat(fnameMask, "\\", MAX_PATH-strlen(fnameMask)-1);
strncat(fnameMask, "*.*", MAX_PATH-strlen(fnameMask)-4);
2001-11-18 10:24:36 +00:00
pdir = (DIR*)malloc(sizeof(DIR)+strlen(fname));
pdir->dd_dir.d_ino = 0;
pdir->dd_dir.d_reclen = 0;
pdir->dd_dir.d_name = 0;
pdir->dd_dir.d_namlen = 0;
2001-11-18 10:24:36 +00:00
pdir->dd_handle = 0;
pdir->dd_stat = 0;
strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */
2001-11-18 10:24:36 +00:00
MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH);
2007-09-18 20:16:33 +00:00
if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE)
2001-11-18 10:24:36 +00:00
{
free(pdir);
return NULL;
}
else
{
WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL);
2001-11-18 10:24:36 +00:00
pdir->dd_dir.d_name = strdup(nameFound);
pdir->dd_dir.d_namlen = strlen(nameFound);
}
return pdir;
}
struct dirent* readdir(DIR* dir)
{
char nameFound[MAX_PATH+1];
static struct dirent dummy;
2007-09-18 20:16:33 +00:00
if (dir->dd_stat == 0)
2001-11-18 10:24:36 +00:00
{
dummy.d_name = ".";
dummy.d_namlen = 1;
dir->dd_stat ++;
return &dummy;
}
2007-09-18 20:16:33 +00:00
else if (dir->dd_stat == 1)
2001-11-18 10:24:36 +00:00
{
dummy.d_name = "..";
dummy.d_namlen = 2;
dir->dd_stat ++;
return &dummy;
}
2007-09-18 20:16:33 +00:00
else if (dir->dd_stat == 2)
2001-11-18 10:24:36 +00:00
{
dir->dd_stat++;
return &dir->dd_dir;
}
else
{
2007-09-18 20:16:33 +00:00
if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0)
2001-11-18 10:24:36 +00:00
{
dir->dd_stat = -1;
return NULL;
}
WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL);
2007-09-18 20:16:33 +00:00
if (dir->dd_dir.d_name)
2001-11-18 10:24:36 +00:00
free(dir->dd_dir.d_name);
2001-11-18 10:24:36 +00:00
dir->dd_dir.d_name = strdup(nameFound);
dir->dd_dir.d_namlen = strlen(nameFound);
2001-11-18 10:24:36 +00:00
dir->dd_stat ++;
2001-11-18 10:24:36 +00:00
return &dir->dd_dir;
}
}
int closedir(DIR* dir)
{
2007-09-18 20:16:33 +00:00
if (dir == NULL)
2001-11-18 10:24:36 +00:00
return 0;
2007-09-18 20:16:33 +00:00
if (dir->dd_handle)
2001-11-18 10:24:36 +00:00
FindClose((HANDLE)dir->dd_handle);
2007-09-18 20:16:33 +00:00
if (dir->dd_dir.d_name)
2001-11-18 10:24:36 +00:00
free(dir->dd_dir.d_name);
free(dir);
return 1;
}
/* Make directory, Unix style */
void mkdir(char* dirname, int mode)
{
char path[MAX_PATH+1];
TCHAR pathUnc[MAX_PATH+1];
char* ptr;
strncpy(path, dirname, MAX_PATH);
2007-09-18 20:16:33 +00:00
if (*path == '/')
2001-11-18 10:24:36 +00:00
*path = '\\';
/* Run through the string and attempt creating all subdirs on the path */
2007-09-18 20:16:33 +00:00
for (ptr = path+1; *ptr; ptr ++)
2001-11-18 10:24:36 +00:00
{
2007-09-18 20:16:33 +00:00
if (*ptr == '\\' || *ptr == '/')
2001-11-18 10:24:36 +00:00
{
*ptr = 0;
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
CreateDirectory(pathUnc, 0);
*ptr = '\\';
}
}
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
CreateDirectory(pathUnc, 0);
}
char *strdup(const char *strSource)
{
char* buffer;
size_z len = strlen(strSource)+1;
buffer = (char*)malloc(len);
2007-09-18 20:16:33 +00:00
if (buffer)
memcpy(buffer, strSource, len);
2001-11-18 10:24:36 +00:00
return buffer;
}
// gcc build only functions follow
#else // defined(__GNUC__)
#ifndef __MINGW32CE__
int islower(int c) {
return (c>='a' && c<='z');
}
int isspace(int c) {
return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v');
}
int isalpha(int c) {
return ((c>='a' && c<='z') || (c>='A' && c<='Z'));
}
int isalnum(int c) {
return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'));
}
int isprint(int c) {
//static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~";
//return (isalnum(c) || strchr(punct, c));
return (32 <= c && c <= 126); // based on BSD manpage
}
#endif
#endif