4 * Copyright (c) Nokia 2004-2005. All rights reserved.
5 * This code is licensed under the same terms as Perl itself.
9 #define SYMBIAN_UTILS_CPP
12 #include <textresolver.h>
22 EXPORT_C int symbian_sys_init(int *argcp, char ***argvp)
24 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
27 (void)times(&PL_timesbase);
30 EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n)
32 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
35 return ((CPerlBase*)PL_appctx)->ConsoleRead(fd, b, n);
37 EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n)
39 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
42 return ((CPerlBase*)PL_appctx)->ConsoleWrite(fd, b, n);
44 static const char NullErr[] = "";
45 EXPORT_C char* symbian_get_error_string(TInt error)
47 // CTextResolver seems to be unreliable, so we roll our own
48 // at least for the basic Symbian errors (but does not work
49 // for the various subsystems).
52 return strerror(error);
53 error = -error; // flip
54 const TInt KErrStringMax = 256;
59 static const kerritem kerrtable[] = {
60 { "None", /* 0 */ "No error"},
61 { "NotFound", /* -1 */ "Unable to find the specified object"},
62 { "General", /* -2 */ "General (unspecified) error"},
63 { "Cancel", /* -3 */ "The operation was cancelled"},
64 { "NoMemory", /* -4 */ "Not enough memory"},
65 { "NotSupported", /* -5 */ "The operation requested is not supported"},
66 { "Argument", /* -6 */ "Bad request"},
67 { "TotalLossOfPrecision",
68 /* -7 */ "Total loss of precision"},
69 { "BadHandle", /* -8 */ "Bad object"},
70 { "Overflow", /* -9 */ "Overflow"},
71 { "Underflow", /* -10 */ "Underflow"},
72 { "AlreadyExists", /* -11 */ "Already exists"},
73 { "PathNotFound", /* -12 */ "Unable to find the specified folder"},
74 { "Died", /* -13 */ "Closed"},
76 "The specified object is currently in use by another program"},
77 { "ServerTerminated", /* -15 */ "Server has closed"},
78 { "ServerBusy", /* -16 */ "Server busy"},
79 { "Completion", /* -17 */ "Completion error"},
80 { "NotReady", /* -18 */ "Not ready"},
81 { "Unknown", /* -19 */ "Unknown error"},
82 { "Corrupt", /* -20 */ "Corrupt"},
83 { "AccessDenied", /* -21 */ "Access denied"},
84 { "Locked", /* -22 */ "Locked"},
85 { "Write", /* -23 */ "Failed to write"},
86 { "DisMounted", /* -24 */ "Wrong disk present"},
87 { "Eof", /* -25 */ "Unexpected end of file"},
88 { "DiskFull", /* -26 */ "Disk full"},
89 { "BadDriver", /* -27 */ "Bad device driver"},
90 { "BadName", /* -28 */ "Bad name"},
91 { "CommsLineFail", /* -29 */ "Comms line failed"},
92 { "CommsFrame", /* -30 */ "Comms frame error"},
93 { "CommsOverrun", /* -31 */ "Comms overrun error"},
94 { "CommsParity", /* -32 */ "Comms parity error"},
95 { "TimedOut", /* -33 */ "Timed out"},
96 { "CouldNotConnect",/* -34 */ "Failed to connect"},
97 { "CouldNotDisconnect",
98 /* -35 */ "Failed to disconnect"},
99 { "Disconnected", /* -36 */ "Disconnected"},
100 { "BadLibraryEntryPoint",
101 /* -37 */ "Bad library entry point"},
102 { "BadDescriptor", /* -38 */ "Bad descriptor"},
103 { "Abort", /* -39 */ "Interrupted"},
104 { "TooBig", /* -40 */ "Too big"},
105 { "DivideByZero", /* -41 */ "Divide by zero"},
106 { "BadPower", /* -42 */ "Batteries too low"},
107 { "DirFull", /* -43 */ "Folder full"},
108 { "KErrHardwareNotAvailable",
109 /* -44 */ "Hardware is not available"},
110 { "SessionClosed", /* -45 */ "Session was closed"},
111 { "PermissionDenied",
112 /* -46 */ "Permission denied"}
114 const TInt n = sizeof(kerrtable) / sizeof(kerritem *);
115 TBuf8<KErrStringMax> buf8;
116 if (error >= 0 && error < n) {
117 const char *kerr = kerrtable[error].kerr;
118 const char *desc = kerrtable[error].desc;
119 const TPtrC8 kerrp((const unsigned char *)kerr, strlen(kerr));
120 const TPtrC8 descp((const unsigned char *)desc, strlen(desc));
121 TBuf8<KErrStringMax> ckerr;
122 TBuf8<KErrStringMax> cdesc;
125 buf8.Format(_L8("K%S (%d) %S"), &ckerr, error, &cdesc);
128 buf8.Format(_L8("Symbian error %d"), error);
130 SV* sv = Perl_get_sv(aTHX_ "\005", TRUE); /* $^E or ${^OS_ERROR} */
132 return (char*)NullErr;
133 sv_setpv(sv, (const char *)buf8.PtrZ());
134 return SvPV_nolen(sv);
136 EXPORT_C void symbian_sleep_usec(const long usec)
138 User::After((TTimeIntervalMicroSeconds32) usec);
140 #define PERL_SYMBIAN_CLK_TCK 100
141 EXPORT_C int symbian_get_cpu_time(long* sec, long* usec)
143 // The RThread().GetCpuTime() does not seem to work?
144 // (it always returns KErrNotSupported)
145 // TTimeIntervalMicroSeconds ti;
146 // TInt err = me.GetCpuTime(ti);
148 TInt periodus; /* tick period in microseconds */
149 if (HAL::Get(HALData::ESystemTickPeriod, periodus) != KErrNone)
151 TUint tick = User::TickCount();
152 if (PL_timesbase.tms_utime == 0) {
153 PL_timesbase.tms_utime = tick;
154 PL_clocktick = PERL_SYMBIAN_CLK_TCK;
156 tick -= PL_timesbase.tms_utime;
157 TInt64 tickus = TInt64(tick) * TInt64(periodus);
158 TInt64 tmps = tickus / 1000000;
159 if (sec) *sec = tmps.Low();
160 if (usec) *usec = tickus.Low() - tmps.Low() * 1000000;
163 EXPORT_C int symbian_usleep(unsigned int usec)
165 if (usec >= 1000000) {
169 symbian_sleep_usec((const long) usec);
172 #define SEC_USEC_TO_CLK_TCK(s, u) \
173 (((s) * PERL_SYMBIAN_CLK_TCK) + (u / (1000000 / PERL_SYMBIAN_CLK_TCK)))
174 EXPORT_C clock_t symbian_times(struct tms *tmsbuf)
177 if (symbian_get_cpu_time(&s, &u) == -1) {
181 tmsbuf->tms_utime = SEC_USEC_TO_CLK_TCK(s, u);
182 tmsbuf->tms_stime = 0;
183 tmsbuf->tms_cutime = 0;
184 tmsbuf->tms_cstime = 0;
185 return tmsbuf->tms_utime;
188 class CE32ProcessWait : public CActive
191 CE32ProcessWait() : CActive(EPriorityStandard) {
192 CActiveScheduler::Add(this);
195 TInt Wait(RThread& aProcess)
197 TInt Wait(RProcess& aProcess)
200 aProcess.Logon(iStatus);
203 CActiveScheduler::Start();
204 return iStatus.Int();
209 CActiveScheduler::Stop();
211 CActiveSchedulerWait iWait;
213 class CSpawnIoRedirect : public CBase
217 // NOTE: there is no real implementation of I/O redirection yet.
221 CSpawnIoRedirect::CSpawnIoRedirect()
225 ESpawnNone = 0x00000000,
226 ESpawnWait = 0x00000001
228 static int symbian_spawn(const TDesC& aFilename,
229 const TDesC& aCommand,
230 const TSpawnFlag aFlag,
231 const CSpawnIoRedirect& aIoRedirect) {
232 TInt error = KErrNone;
234 const TInt KStackSize = 0x1000;
235 const TInt KHeapMin = 0x1000;
236 const TInt KHeapMax = 0x100000;
239 HBufC* command = aCommand.Alloc();
240 error = lib.Load(aFilename);
241 if (error == KErrNone) {
242 TThreadFunction func = (TThreadFunction)(lib.Lookup(1));
244 error = proc.Create(aFilename,
254 error = KErrNotFound;
261 error = proc.Create(aFilename, aCommand);
263 if (error == KErrNone) {
264 if ((TInt)aFlag & (TInt)ESpawnWait) {
265 CE32ProcessWait* w = new CE32ProcessWait();
267 error = w->Wait(proc);
270 error = KErrNoMemory;
277 static int symbian_spawner(const char *command, TSpawnFlag aFlags)
279 TBuf<KMaxFileName> aFilename;
280 TBuf<KMaxFileName> aCommand;
281 TSpawnFlag aSpawnFlags = ESpawnWait;
282 CSpawnIoRedirect iord;
283 char *p = (char*)command;
285 // The recognized syntax is: "cmd [args] [&]". Since one
286 // cannot pass more than (an argv[0] and) an argv[1] to a
287 // Symbian process anyway, not much is done to the cmd or
288 // the args, only backslash quoting.
290 // Strip leading whitespace.
291 while (*p && isspace(*p)) p++;
294 while (*p && !isspace(*p) && *p != '&') {
297 aFilename.Append(p[1]);
303 aFilename.Append(*p);
308 // Skip whitespace between argv[0] and argv[1].
309 while(*p && isspace(*p)) p++;
316 if (isspace(b[-1])) {
318 while (b > a && isspace(*b)) b--;
321 if (b > a && b[-1] == '&') {
322 // Parse backgrounding in any case,
323 // but turn it off only if wanted.
324 if ((aFlags & ESpawnWait))
326 (TSpawnFlag) (aSpawnFlags & ~ESpawnWait);
328 if (isspace(b[-1])) {
330 while (b > a && isspace(*b)) b--;
334 for (p = a; p < b; p++) {
337 aCommand.Append(p[1]);
344 // NOTE: I/O redirection is not yet done.
345 // Implementing that may require a separate server.
348 int spawned = symbian_spawn(aFilename, aCommand, aSpawnFlags, iord);
349 return spawned == KErrNone ? 0 : -1;
351 EXPORT_C int symbian_do_spawn(const char *command)
353 return symbian_spawner(command, ESpawnWait);
355 EXPORT_C int symbian_do_spawn_nowait(const char *command)
357 return symbian_spawner(command, ESpawnNone);
359 EXPORT_C int symbian_do_aspawn(void* vreally, void* vmark, void* sp)