instead of unions use double cast for data pointer <-> function pointer
[p5sagit/p5-mst-13.2.git] / symbian / symbian_utils.cpp
CommitLineData
27da23d5 1/*
2 * symbian_utils.cpp
3 *
4 * Copyright (c) Nokia 2004-2005. All rights reserved.
5 * This code is licensed under the same terms as Perl itself.
6 *
7 */
8
9#define SYMBIAN_UTILS_CPP
10#include <e32base.h>
11#include <e32std.h>
12#include <textresolver.h>
13#include <utf.h>
14#include <hal.h>
15
16#include <string.h>
17#include <ctype.h>
18
19#include "PerlBase.h"
20
21extern "C" {
22 EXPORT_C int symbian_sys_init(int *argcp, char ***argvp)
23 {
24#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
25 dVAR;
26#endif
27 (void)times(&PL_timesbase);
28 return 0;
29 }
30 EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n)
31 {
32#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
33 dVAR;
34#endif
35 return ((CPerlBase*)PL_appctx)->ConsoleRead(fd, b, n);
36 }
37 EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n)
38 {
39#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */
40 dVAR;
41#endif
42 return ((CPerlBase*)PL_appctx)->ConsoleWrite(fd, b, n);
43 }
44 static const char NullErr[] = "";
45 EXPORT_C char* symbian_get_error_string(const TInt error)
46 {
47 dTHX;
48 if (error >= 0)
49 return strerror(error);
50 CTextResolver* textResolver = CTextResolver::NewL();
51 CleanupStack::PushL(textResolver);
52 TBuf<KErrorResolverMaxTextLength> buf16;
53 TBuf8<KErrorResolverMaxTextLength> buf8;
54 if (error != KErrNone)
55 buf16 = textResolver->ResolveError(error);
56 if (buf16.Length()) {
57 if (CnvUtfConverter::ConvertFromUnicodeToUtf8(buf8, buf16) !=
58 KErrNone) {
59 CleanupStack::PopAndDestroy(textResolver);
60 return (char*)NullErr;
61 }
62 }
63 SV* sv = Perl_get_sv(aTHX_ "\005", TRUE); /* $^E or ${^OS_ERROR} */
64 if (!sv)
65 return (char*)NullErr;
66 sv_setpv(sv, (const char *)buf8.PtrZ());
67 SvUTF8_on(sv);
68 CleanupStack::PopAndDestroy(textResolver);
69 return SvPV_nolen(sv);
70 }
71 EXPORT_C void symbian_sleep_usec(const long usec)
72 {
73 User::After((TTimeIntervalMicroSeconds32) usec);
74 }
75#define PERL_SYMBIAN_CLK_TCK 100
76 EXPORT_C int symbian_get_cpu_time(long* sec, long* usec)
77 {
78 // The RThread().GetCpuTime() does not seem to work?
79 // (it always returns KErrNotSupported)
80 // TTimeIntervalMicroSeconds ti;
81 // TInt err = me.GetCpuTime(ti);
82 dTHX;
83 TInt periodus; /* tick period in microseconds */
84 if (HAL::Get(HALData::ESystemTickPeriod, periodus) != KErrNone)
85 return -1;
86 TUint tick = User::TickCount();
87 if (PL_timesbase.tms_utime == 0) {
88 PL_timesbase.tms_utime = tick;
89 PL_clocktick = PERL_SYMBIAN_CLK_TCK;
90 }
91 tick -= PL_timesbase.tms_utime;
92 TInt64 tickus = TInt64(tick) * TInt64(periodus);
93 TInt64 tmps = tickus / 1000000;
94 if (sec) *sec = tmps.Low();
95 if (usec) *usec = tickus.Low() - tmps.Low() * 1000000;
96 return 0;
97 }
98 EXPORT_C int symbian_usleep(unsigned int usec)
99 {
100 if (usec >= 1000000) {
101 errno = EINVAL;
102 return -1;
103 }
104 symbian_sleep_usec((const long) usec);
105 return 0;
106 }
107#define SEC_USEC_TO_CLK_TCK(s, u) \
108 (((s) * PERL_SYMBIAN_CLK_TCK) + (u / (1000000 / PERL_SYMBIAN_CLK_TCK)))
109 EXPORT_C clock_t symbian_times(struct tms *tmsbuf)
110 {
111 long s, u;
112 if (symbian_get_cpu_time(&s, &u) == -1) {
113 errno = EINVAL;
114 return -1;
115 } else {
116 tmsbuf->tms_utime = SEC_USEC_TO_CLK_TCK(s, u);
117 tmsbuf->tms_stime = 0;
118 tmsbuf->tms_cutime = 0;
119 tmsbuf->tms_cstime = 0;
120 return tmsbuf->tms_utime;
121 }
122 }
123 class CE32ProcessWait : public CActive
124 {
125 public:
126 CE32ProcessWait() : CActive(EPriorityStandard) {
127 CActiveScheduler::Add(this);
128 }
129#ifdef __WINS__
130 TInt Wait(RThread& aProcess)
131#else
132 TInt Wait(RProcess& aProcess)
133#endif
134 {
135 aProcess.Logon(iStatus);
136 aProcess.Resume();
137 SetActive();
138 CActiveScheduler::Start();
139 return iStatus.Int();
140 }
141 private:
142 void DoCancel() {;}
143 void RunL() {
144 CActiveScheduler::Stop();
145 }
146 CActiveSchedulerWait iWait;
147 };
148 class CSpawnIoRedirect : public CBase
149 {
150 public:
151 CSpawnIoRedirect();
152 // NOTE: there is no real implementation of I/O redirection yet.
153 protected:
154 private:
155 };
156 CSpawnIoRedirect::CSpawnIoRedirect()
157 {
158 }
159 typedef enum {
160 ESpawnNone = 0x00000000,
161 ESpawnWait = 0x00000001
162 } TSpawnFlag;
163 static int symbian_spawn(const TDesC& aFilename,
164 const TDesC& aCommand,
165 const TSpawnFlag aFlag,
166 const CSpawnIoRedirect& aIoRedirect) {
167 TInt error = KErrNone;
168#ifdef __WINS__
169 const TInt KStackSize = 0x1000;
170 const TInt KHeapMin = 0x1000;
171 const TInt KHeapMax = 0x100000;
172 RThread proc;
173 RLibrary lib;
174 HBufC* command = aCommand.Alloc();
175 error = lib.Load(aFilename);
176 if (error == KErrNone) {
177 TThreadFunction func = (TThreadFunction)(lib.Lookup(1));
178 if (func)
179 error = proc.Create(aFilename,
180 func,
181 KStackSize,
182 (TAny*)command,
183 &lib,
184 RThread().Heap(),
185 KHeapMin,
186 KHeapMax,
187 EOwnerProcess);
188 else
189 error = KErrNotFound;
190 lib.Close();
191 }
192 else
193 delete command;
194#else
195 RProcess proc;
196 error = proc.Create(aFilename, aCommand);
197#endif
198 if (error == KErrNone) {
199 if ((TInt)aFlag & (TInt)ESpawnWait) {
200 CE32ProcessWait* w = new CE32ProcessWait();
201 if (w) {
202 error = w->Wait(proc);
203 delete w;
204 } else
205 error = KErrNoMemory;
206 } else
207 proc.Resume();
208 proc.Close();
209 }
210 return error;
211 }
212 static int symbian_spawner(const char *command, TSpawnFlag aFlags)
213 {
214 TBuf<KMaxFileName> aFilename;
215 TBuf<KMaxFileName> aCommand;
216 TSpawnFlag aSpawnFlags = ESpawnWait;
217 CSpawnIoRedirect iord;
218 char *p = (char*)command;
219
220 // The recognized syntax is: "cmd [args] [&]". Since one
221 // cannot pass more than (an argv[0] and) an argv[1] to a
222 // Symbian process anyway, not much is done to the cmd or
223 // the args, only backslash quoting.
224
225 // Strip leading whitespace.
226 while (*p && isspace(*p)) p++;
227 if (*p) {
228 // Build argv[0].
229 while (*p && !isspace(*p) && *p != '&') {
230 if (*p == '\\') {
231 if (p[1]) {
232 aFilename.Append(p[1]);
233 p++;
234 }
235
236 }
237 else
238 aFilename.Append(*p);
239 p++;
240 }
241
242 if (*p) {
243 // Skip whitespace between argv[0] and argv[1].
244 while(*p && isspace(*p)) p++;
245 // Build argv[1].
246 if (*p) {
247 char *a = p;
248 char *b = p + 1;
249
250 while (*b) b++;
251 if (isspace(b[-1])) {
252 b--;
253 while (b > a && isspace(*b)) b--;
254 b++;
255 }
256 if (b > a && b[-1] == '&') {
257 // Parse backgrounding in any case,
258 // but turn it off only if wanted.
259 if ((aFlags & ESpawnWait))
260 aSpawnFlags =
261 (TSpawnFlag) (aSpawnFlags & ~ESpawnWait);
262 b--;
263 if (isspace(b[-1])) {
264 b--;
265 while (b > a && isspace(*b)) b--;
266 b++;
267 }
268 }
269 for (p = a; p < b; p++) {
270 if (*p == '\\') {
271 if (p[1])
272 aCommand.Append(p[1]);
273 p++;
274 }
275 else
276 aCommand.Append(*p);
277 }
278 }
279 // NOTE: I/O redirection is not yet done.
280 // Implementing that may require a separate server.
281 }
282 }
283 int spawned = symbian_spawn(aFilename, aCommand, aSpawnFlags, iord);
284 return spawned == KErrNone ? 0 : -1;
285 }
286 EXPORT_C int symbian_do_spawn(const char *command)
287 {
288 return symbian_spawner(command, ESpawnWait);
289 }
290 EXPORT_C int symbian_do_spawn_nowait(const char *command)
291 {
292 return symbian_spawner(command, ESpawnNone);
293 }
294 EXPORT_C int symbian_do_aspawn(void* vreally, void* vmark, void* sp)
295 {
296 return -1;
297 }
298}
299