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
29 EXPORT_C int symbian_sys_init(int *argcp, char ***argvp)
31 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
34 (void)times(&PL_timesbase);
37 XS(XS_PerlApp_TextQuery) // Can't be made static because of XS().
41 Perl_croak(aTHX_ "PerlApp::TextQuery: no arguments, please");
43 // TODO: parse arguments for title, prompt, and maxsize.
45 // TextQuery(title => ..., prompt => ..., maxsize => ...)
46 // For an example see e.g. universal.c:XS_PerlIO_get_layers().
47 _LIT(KTitle, "Title");
48 _LIT(KPrompt, "Prompt");
49 HBufC* cData = HBufC::New(KPerlUiOneLinerSize);
50 TBool cSuccess = EFalse;
52 TPtr cPtr(cData->Des());
53 if (CPerlUi::TextQueryDialogL(KTitle,
56 KPerlUiOneLinerSize)) {
57 ST(0) = sv_2mortal(PerlUtil::newSvPVfromTDesC16(*cData));
67 EXPORT_C void init_os_extras(void)
70 char *file = __FILE__;
72 newXS("PerlApp::TextQuery", XS_PerlApp_TextQuery, file);
74 EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n)
76 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
79 return ((CPerlBase*)PL_appctx)->ConsoleRead(fd, b, n);
81 EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n)
83 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
86 return ((CPerlBase*)PL_appctx)->ConsoleWrite(fd, b, n);
88 static const char NullErr[] = "";
89 EXPORT_C char* symbian_get_error_string(TInt error)
91 // CTextResolver seems to be unreliable, so we roll our own
92 // at least for the basic Symbian errors (this does not cover
93 // the various subsystems).
96 return strerror(error);
97 error = -error; // flip
98 const TInt KErrStringMax = 256;
103 static const kerritem kerrtable[] = {
104 { "None", /* 0 */ "No error"},
105 { "NotFound", /* -1 */ "Unable to find the specified object"},
106 { "General", /* -2 */ "General (unspecified) error"},
107 { "Cancel", /* -3 */ "The operation was cancelled"},
108 { "NoMemory", /* -4 */ "Not enough memory"},
109 { "NotSupported", /* -5 */ "The operation requested is not supported"},
110 { "Argument", /* -6 */ "Bad request"},
111 { "TotalLossOfPrecision",
112 /* -7 */ "Total loss of precision"},
113 { "BadHandle", /* -8 */ "Bad object"},
114 { "Overflow", /* -9 */ "Overflow"},
115 { "Underflow", /* -10 */ "Underflow"},
116 { "AlreadyExists", /* -11 */ "Already exists"},
117 { "PathNotFound", /* -12 */ "Unable to find the specified folder"},
118 { "Died", /* -13 */ "Closed"},
120 "The specified object is currently in use by another program"},
121 { "ServerTerminated", /* -15 */ "Server has closed"},
122 { "ServerBusy", /* -16 */ "Server busy"},
123 { "Completion", /* -17 */ "Completion error"},
124 { "NotReady", /* -18 */ "Not ready"},
125 { "Unknown", /* -19 */ "Unknown error"},
126 { "Corrupt", /* -20 */ "Corrupt"},
127 { "AccessDenied", /* -21 */ "Access denied"},
128 { "Locked", /* -22 */ "Locked"},
129 { "Write", /* -23 */ "Failed to write"},
130 { "DisMounted", /* -24 */ "Wrong disk present"},
131 { "Eof", /* -25 */ "Unexpected end of file"},
132 { "DiskFull", /* -26 */ "Disk full"},
133 { "BadDriver", /* -27 */ "Bad device driver"},
134 { "BadName", /* -28 */ "Bad name"},
135 { "CommsLineFail", /* -29 */ "Comms line failed"},
136 { "CommsFrame", /* -30 */ "Comms frame error"},
137 { "CommsOverrun", /* -31 */ "Comms overrun error"},
138 { "CommsParity", /* -32 */ "Comms parity error"},
139 { "TimedOut", /* -33 */ "Timed out"},
140 { "CouldNotConnect",/* -34 */ "Failed to connect"},
141 { "CouldNotDisconnect",
142 /* -35 */ "Failed to disconnect"},
143 { "Disconnected", /* -36 */ "Disconnected"},
144 { "BadLibraryEntryPoint",
145 /* -37 */ "Bad library entry point"},
146 { "BadDescriptor", /* -38 */ "Bad descriptor"},
147 { "Abort", /* -39 */ "Interrupted"},
148 { "TooBig", /* -40 */ "Too big"},
149 { "DivideByZero", /* -41 */ "Divide by zero"},
150 { "BadPower", /* -42 */ "Batteries too low"},
151 { "DirFull", /* -43 */ "Folder full"},
152 { "KErrHardwareNotAvailable",
153 /* -44 */ "Hardware is not available"},
154 { "SessionClosed", /* -45 */ "Session was closed"},
155 { "PermissionDenied",
156 /* -46 */ "Permission denied"}
158 const TInt n = sizeof(kerrtable) / sizeof(kerritem *);
159 TBuf8<KErrStringMax> buf8;
160 if (error >= 0 && error < n) {
161 const char *kerr = kerrtable[error].kerr;
162 const char *desc = kerrtable[error].desc;
163 const TPtrC8 kerrp((const unsigned char *)kerr, strlen(kerr));
164 const TPtrC8 descp((const unsigned char *)desc, strlen(desc));
165 TBuf8<KErrStringMax> ckerr;
166 TBuf8<KErrStringMax> cdesc;
169 buf8.Format(_L8("K%S (%d) %S"), &ckerr, error, &cdesc);
172 buf8.Format(_L8("Symbian error %d"), error);
174 SV* sv = Perl_get_sv(aTHX_ "\005", GV_ADD); /* $^E or ${^OS_ERROR} */
176 return (char*)NullErr;
177 sv_setpv(sv, (const char *)buf8.PtrZ());
178 return SvPV_nolen(sv);
180 EXPORT_C void symbian_sleep_usec(const long usec)
182 User::After((TTimeIntervalMicroSeconds32) usec);
184 #define PERL_SYMBIAN_CLK_TCK 100
185 EXPORT_C int symbian_get_cpu_time(long* sec, long* usec)
187 // The RThread().GetCpuTime() does not seem to work?
188 // (it always returns KErrNotSupported)
189 // TTimeIntervalMicroSeconds ti;
190 // TInt err = me.GetCpuTime(ti);
192 TInt periodus; /* tick period in microseconds */
193 if (HAL::Get(HALData::ESystemTickPeriod, periodus) != KErrNone)
195 TUint tick = User::TickCount();
196 if (PL_timesbase.tms_utime == 0) {
197 PL_timesbase.tms_utime = tick;
198 PL_clocktick = PERL_SYMBIAN_CLK_TCK;
200 tick -= PL_timesbase.tms_utime;
201 TInt64 tickus = TInt64(tick) * TInt64(periodus);
202 TInt64 tmps = tickus / 1000000;
203 if (sec) *sec = tmps.Low();
204 if (usec) *usec = tickus.Low() - tmps.Low() * 1000000;
207 EXPORT_C int symbian_usleep(unsigned int usec)
209 if (usec >= 1000000) {
213 symbian_sleep_usec((const long) usec);
216 #define SEC_USEC_TO_CLK_TCK(s, u) \
217 (((s) * PERL_SYMBIAN_CLK_TCK) + (u / (1000000 / PERL_SYMBIAN_CLK_TCK)))
218 EXPORT_C clock_t symbian_times(struct tms *tmsbuf)
221 if (symbian_get_cpu_time(&s, &u) == -1) {
225 tmsbuf->tms_utime = SEC_USEC_TO_CLK_TCK(s, u);
226 tmsbuf->tms_stime = 0;
227 tmsbuf->tms_cutime = 0;
228 tmsbuf->tms_cstime = 0;
229 return tmsbuf->tms_utime;
232 class CProcessWait : public CActive
235 CProcessWait() : CActive(EPriorityStandard) {
236 CActiveScheduler::Add(this);
239 TInt Wait(RThread& aProcess)
241 TInt Wait(RProcess& aProcess)
244 aProcess.Logon(iStatus);
247 CActiveScheduler::Start();
248 return iStatus.Int();
253 CActiveScheduler::Stop();
256 class CSpawnIoRedirect : public CBase
260 // NOTE: there is no real implementation of I/O redirection yet.
264 CSpawnIoRedirect::CSpawnIoRedirect()
268 ESpawnNone = 0x00000000,
269 ESpawnWait = 0x00000001
271 static int symbian_spawn(const TDesC& aFilename,
272 const TDesC& aCommand,
273 const TSpawnFlag aFlag,
274 const CSpawnIoRedirect& aIoRedirect) {
275 TInt error = KErrNone;
277 const TInt KStackSize = 0x1000;
278 const TInt KHeapMin = 0x1000;
279 const TInt KHeapMax = 0x100000;
282 HBufC* command = aCommand.Alloc();
283 error = lib.Load(aFilename);
284 if (error == KErrNone) {
285 TThreadFunction func = (TThreadFunction)(lib.Lookup(1));
287 error = proc.Create(aFilename,
297 error = KErrNotFound;
304 error = proc.Create(aFilename, aCommand);
306 if (error == KErrNone) {
307 if ((TInt)aFlag & (TInt)ESpawnWait) {
308 CProcessWait* w = new CProcessWait();
310 error = w->Wait(proc);
313 error = KErrNoMemory;
320 static int symbian_spawner(const char *command, TSpawnFlag aFlags)
322 TBuf<KMaxFileName> aFilename;
323 TBuf<KMaxFileName> aCommand;
324 TSpawnFlag aSpawnFlags = ESpawnWait;
325 CSpawnIoRedirect iord;
326 char *p = (char*)command;
328 // The recognized syntax is: "cmd [args] [&]". Since one
329 // cannot pass more than (an argv[0] and) an argv[1] to a
330 // Symbian process anyway, not much is done to the cmd or
331 // the args, only backslash quoting.
333 // Strip leading whitespace.
334 while (*p && isspace(*p)) p++;
337 while (*p && !isspace(*p) && *p != '&') {
340 aFilename.Append(p[1]);
346 aFilename.Append(*p);
351 // Skip whitespace between argv[0] and argv[1].
352 while(*p && isspace(*p)) p++;
359 if (isspace(b[-1])) {
361 while (b > a && isspace(*b)) b--;
364 if (b > a && b[-1] == '&') {
365 // Parse backgrounding in any case,
366 // but turn it off only if wanted.
367 if ((aFlags & ESpawnWait))
369 (TSpawnFlag) (aSpawnFlags & ~ESpawnWait);
371 if (isspace(b[-1])) {
373 while (b > a && isspace(*b)) b--;
377 for (p = a; p < b; p++) {
380 aCommand.Append(p[1]);
387 // NOTE: I/O redirection is not yet done.
388 // Implementing that may require a separate server.
391 int spawned = symbian_spawn(aFilename, aCommand, aSpawnFlags, iord);
392 return spawned == KErrNone ? 0 : -1;
394 EXPORT_C int symbian_do_spawn(const char *command)
396 return symbian_spawner(command, ESpawnWait);
398 EXPORT_C int symbian_do_spawn_nowait(const char *command)
400 return symbian_spawner(command, ESpawnNone);
402 EXPORT_C int symbian_do_aspawn(void* vreally, void* vmark, void* sp)