Mark a static function as static
[p5sagit/p5-mst-13.2.git] / symbian / symbian_utils.cpp
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
21 extern "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