/* * 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 #include #include #include #include #include #include #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 buf16; TBuf8 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 aFilename; TBuf 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; } }