diff options
Diffstat (limited to 'symbian/symbian_utils.cpp')
-rw-r--r-- | symbian/symbian_utils.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/symbian/symbian_utils.cpp b/symbian/symbian_utils.cpp new file mode 100644 index 0000000000..16e911c81e --- /dev/null +++ b/symbian/symbian_utils.cpp @@ -0,0 +1,299 @@ +/* + * symbian_utils.cpp + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#define SYMBIAN_UTILS_CPP +#include <e32base.h> +#include <e32std.h> +#include <textresolver.h> +#include <utf.h> +#include <hal.h> + +#include <string.h> +#include <ctype.h> + +#include "PerlBase.h" + +extern "C" { + EXPORT_C int symbian_sys_init(int *argcp, char ***argvp) + { +#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ + dVAR; +#endif + (void)times(&PL_timesbase); + return 0; + } + EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n) + { +#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ + dVAR; +#endif + return ((CPerlBase*)PL_appctx)->ConsoleRead(fd, b, n); + } + EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n) + { +#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ + dVAR; +#endif + return ((CPerlBase*)PL_appctx)->ConsoleWrite(fd, b, n); + } + static const char NullErr[] = ""; + EXPORT_C char* symbian_get_error_string(const TInt error) + { + dTHX; + if (error >= 0) + return strerror(error); + CTextResolver* textResolver = CTextResolver::NewL(); + CleanupStack::PushL(textResolver); + TBuf<KErrorResolverMaxTextLength> buf16; + TBuf8<KErrorResolverMaxTextLength> buf8; + if (error != KErrNone) + buf16 = textResolver->ResolveError(error); + if (buf16.Length()) { + if (CnvUtfConverter::ConvertFromUnicodeToUtf8(buf8, buf16) != + KErrNone) { + CleanupStack::PopAndDestroy(textResolver); + return (char*)NullErr; + } + } + SV* sv = Perl_get_sv(aTHX_ "\005", TRUE); /* $^E or ${^OS_ERROR} */ + if (!sv) + return (char*)NullErr; + sv_setpv(sv, (const char *)buf8.PtrZ()); + SvUTF8_on(sv); + CleanupStack::PopAndDestroy(textResolver); + return SvPV_nolen(sv); + } + EXPORT_C void symbian_sleep_usec(const long usec) + { + User::After((TTimeIntervalMicroSeconds32) usec); + } +#define PERL_SYMBIAN_CLK_TCK 100 + EXPORT_C int symbian_get_cpu_time(long* sec, long* usec) + { + // The RThread().GetCpuTime() does not seem to work? + // (it always returns KErrNotSupported) + // TTimeIntervalMicroSeconds ti; + // TInt err = me.GetCpuTime(ti); + dTHX; + TInt periodus; /* tick period in microseconds */ + if (HAL::Get(HALData::ESystemTickPeriod, periodus) != KErrNone) + return -1; + TUint tick = User::TickCount(); + if (PL_timesbase.tms_utime == 0) { + PL_timesbase.tms_utime = tick; + PL_clocktick = PERL_SYMBIAN_CLK_TCK; + } + tick -= PL_timesbase.tms_utime; + TInt64 tickus = TInt64(tick) * TInt64(periodus); + TInt64 tmps = tickus / 1000000; + if (sec) *sec = tmps.Low(); + if (usec) *usec = tickus.Low() - tmps.Low() * 1000000; + return 0; + } + EXPORT_C int symbian_usleep(unsigned int usec) + { + if (usec >= 1000000) { + errno = EINVAL; + return -1; + } + symbian_sleep_usec((const long) usec); + return 0; + } +#define SEC_USEC_TO_CLK_TCK(s, u) \ + (((s) * PERL_SYMBIAN_CLK_TCK) + (u / (1000000 / PERL_SYMBIAN_CLK_TCK))) + EXPORT_C clock_t symbian_times(struct tms *tmsbuf) + { + long s, u; + if (symbian_get_cpu_time(&s, &u) == -1) { + errno = EINVAL; + return -1; + } else { + tmsbuf->tms_utime = SEC_USEC_TO_CLK_TCK(s, u); + tmsbuf->tms_stime = 0; + tmsbuf->tms_cutime = 0; + tmsbuf->tms_cstime = 0; + return tmsbuf->tms_utime; + } + } + class CE32ProcessWait : public CActive + { + public: + CE32ProcessWait() : CActive(EPriorityStandard) { + CActiveScheduler::Add(this); + } +#ifdef __WINS__ + TInt Wait(RThread& aProcess) +#else + TInt Wait(RProcess& aProcess) +#endif + { + aProcess.Logon(iStatus); + aProcess.Resume(); + SetActive(); + CActiveScheduler::Start(); + return iStatus.Int(); + } + private: + void DoCancel() {;} + void RunL() { + CActiveScheduler::Stop(); + } + CActiveSchedulerWait iWait; + }; + class CSpawnIoRedirect : public CBase + { + public: + CSpawnIoRedirect(); + // NOTE: there is no real implementation of I/O redirection yet. + protected: + private: + }; + CSpawnIoRedirect::CSpawnIoRedirect() + { + } + typedef enum { + ESpawnNone = 0x00000000, + ESpawnWait = 0x00000001 + } TSpawnFlag; + static int symbian_spawn(const TDesC& aFilename, + const TDesC& aCommand, + const TSpawnFlag aFlag, + const CSpawnIoRedirect& aIoRedirect) { + TInt error = KErrNone; +#ifdef __WINS__ + const TInt KStackSize = 0x1000; + const TInt KHeapMin = 0x1000; + const TInt KHeapMax = 0x100000; + RThread proc; + RLibrary lib; + HBufC* command = aCommand.Alloc(); + error = lib.Load(aFilename); + if (error == KErrNone) { + TThreadFunction func = (TThreadFunction)(lib.Lookup(1)); + if (func) + error = proc.Create(aFilename, + func, + KStackSize, + (TAny*)command, + &lib, + RThread().Heap(), + KHeapMin, + KHeapMax, + EOwnerProcess); + else + error = KErrNotFound; + lib.Close(); + } + else + delete command; +#else + RProcess proc; + error = proc.Create(aFilename, aCommand); +#endif + if (error == KErrNone) { + if ((TInt)aFlag & (TInt)ESpawnWait) { + CE32ProcessWait* w = new CE32ProcessWait(); + if (w) { + error = w->Wait(proc); + delete w; + } else + error = KErrNoMemory; + } else + proc.Resume(); + proc.Close(); + } + return error; + } + static int symbian_spawner(const char *command, TSpawnFlag aFlags) + { + TBuf<KMaxFileName> aFilename; + TBuf<KMaxFileName> aCommand; + TSpawnFlag aSpawnFlags = ESpawnWait; + CSpawnIoRedirect iord; + char *p = (char*)command; + + // The recognized syntax is: "cmd [args] [&]". Since one + // cannot pass more than (an argv[0] and) an argv[1] to a + // Symbian process anyway, not much is done to the cmd or + // the args, only backslash quoting. + + // Strip leading whitespace. + while (*p && isspace(*p)) p++; + if (*p) { + // Build argv[0]. + while (*p && !isspace(*p) && *p != '&') { + if (*p == '\\') { + if (p[1]) { + aFilename.Append(p[1]); + p++; + } + + } + else + aFilename.Append(*p); + p++; + } + + if (*p) { + // Skip whitespace between argv[0] and argv[1]. + while(*p && isspace(*p)) p++; + // Build argv[1]. + if (*p) { + char *a = p; + char *b = p + 1; + + while (*b) b++; + if (isspace(b[-1])) { + b--; + while (b > a && isspace(*b)) b--; + b++; + } + if (b > a && b[-1] == '&') { + // Parse backgrounding in any case, + // but turn it off only if wanted. + if ((aFlags & ESpawnWait)) + aSpawnFlags = + (TSpawnFlag) (aSpawnFlags & ~ESpawnWait); + b--; + if (isspace(b[-1])) { + b--; + while (b > a && isspace(*b)) b--; + b++; + } + } + for (p = a; p < b; p++) { + if (*p == '\\') { + if (p[1]) + aCommand.Append(p[1]); + p++; + } + else + aCommand.Append(*p); + } + } + // NOTE: I/O redirection is not yet done. + // Implementing that may require a separate server. + } + } + int spawned = symbian_spawn(aFilename, aCommand, aSpawnFlags, iord); + return spawned == KErrNone ? 0 : -1; + } + EXPORT_C int symbian_do_spawn(const char *command) + { + return symbian_spawner(command, ESpawnWait); + } + EXPORT_C int symbian_do_spawn_nowait(const char *command) + { + return symbian_spawner(command, ESpawnNone); + } + EXPORT_C int symbian_do_aspawn(void* vreally, void* vmark, void* sp) + { + return -1; + } +} + |