summaryrefslogtreecommitdiff
path: root/symbian/symbian_utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'symbian/symbian_utils.cpp')
-rw-r--r--symbian/symbian_utils.cpp299
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;
+ }
+}
+