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 <utf.h> 13 #include <hal.h> 14 15 #include <eikenv.h> 16 17 #include <string.h> 18 #include <ctype.h> 19 20 #include "PerlUi.h" 21 #include "PerlBase.h" 22 #include "PerlUtil.h" 23 24 #include "EXTERN.h" 25 #include "perl.h" 26 #include "XSUB.h" 27 28 extern "C" { symbian_sys_init(int * argcp,char *** argvp)29 EXPORT_C int symbian_sys_init(int *argcp, char ***argvp) 30 { 31 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ 32 dVAR; 33 #endif 34 (void)times(&PL_timesbase); 35 return 0; 36 } XS(XS_PerlApp_TextQuery)37 XS(XS_PerlApp_TextQuery) // Can't be made static because of XS(). 38 { 39 dXSARGS; 40 if (items != 0) 41 Perl_croak(aTHX_ "PerlApp::TextQuery: no arguments, please"); 42 SP -= items; 43 // TODO: parse arguments for title, prompt, and maxsize. 44 // Suggested syntax: 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; 51 if (cData) { 52 TPtr cPtr(cData->Des()); 53 if (CPerlUi::TextQueryDialogL(KTitle, 54 KPrompt, 55 cPtr, 56 KPerlUiOneLinerSize)) { 57 ST(0) = sv_2mortal(PerlUtil::newSvPVfromTDesC16(*cData)); 58 cSuccess = ETrue; 59 } 60 delete cData; 61 } 62 if (cSuccess) 63 XSRETURN(1); 64 else 65 XSRETURN_UNDEF; 66 } init_os_extras(void)67 EXPORT_C void init_os_extras(void) 68 { 69 dTHX; 70 char *file = __FILE__; 71 dXSUB_SYS; 72 newXS("PerlApp::TextQuery", XS_PerlApp_TextQuery, file); 73 } symbian_read_stdin(const int fd,char * b,int n)74 EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n) 75 { 76 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ 77 dVAR; 78 #endif 79 if(!PL_appctx) 80 ((CPerlBase*)PL_appctx) = CPerlBase::NewInterpreter(); 81 return ((CPerlBase*)PL_appctx)->ConsoleRead(fd, b, n); 82 } symbian_write_stdout(const int fd,const char * b,int n)83 EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n) 84 { 85 #ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ 86 dVAR; 87 #endif 88 if(!PL_appctx) 89 ((CPerlBase*)PL_appctx) = CPerlBase::NewInterpreter(); 90 return ((CPerlBase*)PL_appctx)->ConsoleWrite(fd, b, n); 91 } 92 static const char NullErr[] = ""; symbian_get_error_string(TInt error)93 EXPORT_C char* symbian_get_error_string(TInt error) 94 { 95 // CTextResolver seems to be unreliable, so we roll our own 96 // at least for the basic Symbian errors (this does not cover 97 // the various subsystems). 98 dTHX; 99 if (error >= 0) 100 return strerror(error); 101 error = -error; // flip 102 const TInt KErrStringMax = 256; 103 typedef struct { 104 const char* kerr; 105 const char* desc; 106 } kerritem; 107 static const kerritem kerrtable[] = { 108 { "None", /* 0 */ "No error"}, 109 { "NotFound", /* -1 */ "Unable to find the specified object"}, 110 { "General", /* -2 */ "General (unspecified) error"}, 111 { "Cancel", /* -3 */ "The operation was cancelled"}, 112 { "NoMemory", /* -4 */ "Not enough memory"}, 113 { "NotSupported", /* -5 */ "The operation requested is not supported"}, 114 { "Argument", /* -6 */ "Bad request"}, 115 { "TotalLossOfPrecision", 116 /* -7 */ "Total loss of precision"}, 117 { "BadHandle", /* -8 */ "Bad object"}, 118 { "Overflow", /* -9 */ "Overflow"}, 119 { "Underflow", /* -10 */ "Underflow"}, 120 { "AlreadyExists", /* -11 */ "Already exists"}, 121 { "PathNotFound", /* -12 */ "Unable to find the specified folder"}, 122 { "Died", /* -13 */ "Closed"}, 123 { "InUse", /* -14 */ 124 "The specified object is currently in use by another program"}, 125 { "ServerTerminated", /* -15 */ "Server has closed"}, 126 { "ServerBusy", /* -16 */ "Server busy"}, 127 { "Completion", /* -17 */ "Completion error"}, 128 { "NotReady", /* -18 */ "Not ready"}, 129 { "Unknown", /* -19 */ "Unknown error"}, 130 { "Corrupt", /* -20 */ "Corrupt"}, 131 { "AccessDenied", /* -21 */ "Access denied"}, 132 { "Locked", /* -22 */ "Locked"}, 133 { "Write", /* -23 */ "Failed to write"}, 134 { "DisMounted", /* -24 */ "Wrong disk present"}, 135 { "Eof", /* -25 */ "Unexpected end of file"}, 136 { "DiskFull", /* -26 */ "Disk full"}, 137 { "BadDriver", /* -27 */ "Bad device driver"}, 138 { "BadName", /* -28 */ "Bad name"}, 139 { "CommsLineFail", /* -29 */ "Comms line failed"}, 140 { "CommsFrame", /* -30 */ "Comms frame error"}, 141 { "CommsOverrun", /* -31 */ "Comms overrun error"}, 142 { "CommsParity", /* -32 */ "Comms parity error"}, 143 { "TimedOut", /* -33 */ "Timed out"}, 144 { "CouldNotConnect",/* -34 */ "Failed to connect"}, 145 { "CouldNotDisconnect", 146 /* -35 */ "Failed to disconnect"}, 147 { "Disconnected", /* -36 */ "Disconnected"}, 148 { "BadLibraryEntryPoint", 149 /* -37 */ "Bad library entry point"}, 150 { "BadDescriptor", /* -38 */ "Bad descriptor"}, 151 { "Abort", /* -39 */ "Interrupted"}, 152 { "TooBig", /* -40 */ "Too big"}, 153 { "DivideByZero", /* -41 */ "Divide by zero"}, 154 { "BadPower", /* -42 */ "Batteries too low"}, 155 { "DirFull", /* -43 */ "Folder full"}, 156 { "KErrHardwareNotAvailable", 157 /* -44 */ "Hardware is not available"}, 158 { "SessionClosed", /* -45 */ "Session was closed"}, 159 { "PermissionDenied", 160 /* -46 */ "Permission denied"} 161 }; 162 const TInt n = sizeof(kerrtable) / sizeof(kerritem *); 163 TBuf8<KErrStringMax> buf8; 164 if (error >= 0 && error < n) { 165 const char *kerr = kerrtable[error].kerr; 166 const char *desc = kerrtable[error].desc; 167 const TPtrC8 kerrp((const unsigned char *)kerr, strlen(kerr)); 168 const TPtrC8 descp((const unsigned char *)desc, strlen(desc)); 169 TBuf8<KErrStringMax> ckerr; 170 TBuf8<KErrStringMax> cdesc; 171 ckerr.Copy(kerrp); 172 cdesc.Copy(descp); 173 buf8.Format(_L8("K%S (%d) %S"), &ckerr, error, &cdesc); 174 175 } else { 176 buf8.Format(_L8("Symbian error %d"), error); 177 } 178 SV* sv = Perl_get_sv(aTHX_ "\005", TRUE); /* $^E or ${^OS_ERROR} */ 179 if (!sv) 180 return (char*)NullErr; 181 sv_setpv(sv, (const char *)buf8.PtrZ()); 182 return SvPV_nolen(sv); 183 } symbian_sleep_usec(const long usec)184 EXPORT_C void symbian_sleep_usec(const long usec) 185 { 186 User::After((TTimeIntervalMicroSeconds32) usec); 187 } 188 #define PERL_SYMBIAN_CLK_TCK 100 symbian_get_cpu_time(long * sec,long * usec)189 EXPORT_C int symbian_get_cpu_time(long* sec, long* usec) 190 { 191 // The RThread().GetCpuTime() does not seem to work? 192 // (it always returns KErrNotSupported) 193 // TTimeIntervalMicroSeconds ti; 194 // TInt err = me.GetCpuTime(ti); 195 dTHX; 196 TInt periodus; /* tick period in microseconds */ 197 if (HAL::Get(HALData::ESystemTickPeriod, periodus) != KErrNone) 198 return -1; 199 TUint tick = User::TickCount(); 200 if (PL_timesbase.tms_utime == 0) { 201 PL_timesbase.tms_utime = tick; 202 PL_clocktick = PERL_SYMBIAN_CLK_TCK; 203 } 204 tick -= PL_timesbase.tms_utime; 205 TInt64 tickus = TInt64(tick) * TInt64(periodus); 206 TInt64 tmps = tickus / 1000000; 207 #ifdef __SERIES60_3X__ 208 if (sec) *sec = I64LOW(tmps); 209 if (usec) *usec = I64LOW(tickus) - I64LOW(tmps) * 1000000; 210 #else 211 if (sec) *sec = tmps.Low(); 212 if (usec) *usec = tickus.Low() - tmps.Low() * 1000000; 213 #endif //__SERIES60_3X__ 214 return 0; 215 } symbian_usleep(unsigned int usec)216 EXPORT_C int symbian_usleep(unsigned int usec) 217 { 218 if (usec >= 1000000) { 219 errno = EINVAL; 220 return -1; 221 } 222 symbian_sleep_usec((const long) usec); 223 return 0; 224 } 225 #define SEC_USEC_TO_CLK_TCK(s, u) \ 226 (((s) * PERL_SYMBIAN_CLK_TCK) + (u / (1000000 / PERL_SYMBIAN_CLK_TCK))) symbian_times(struct tms * tmsbuf)227 EXPORT_C clock_t symbian_times(struct tms *tmsbuf) 228 { 229 long s, u; 230 if (symbian_get_cpu_time(&s, &u) == -1) { 231 errno = EINVAL; 232 return -1; 233 } else { 234 tmsbuf->tms_utime = SEC_USEC_TO_CLK_TCK(s, u); 235 tmsbuf->tms_stime = 0; 236 tmsbuf->tms_cutime = 0; 237 tmsbuf->tms_cstime = 0; 238 return tmsbuf->tms_utime; 239 } 240 } 241 class CProcessWait : public CActive 242 { 243 public: CProcessWait()244 CProcessWait() : CActive(EPriorityStandard) { 245 CActiveScheduler::Add(this); 246 } 247 #ifdef __WINS__ Wait(RThread & aProcess)248 TInt Wait(RThread& aProcess) 249 #else 250 TInt Wait(RProcess& aProcess) 251 #endif 252 { 253 aProcess.Logon(iStatus); 254 aProcess.Resume(); 255 SetActive(); 256 CActiveScheduler::Start(); 257 return iStatus.Int(); 258 } 259 private: DoCancel()260 void DoCancel() {;} RunL()261 void RunL() { 262 CActiveScheduler::Stop(); 263 } 264 }; 265 class CSpawnIoRedirect : public CBase 266 { 267 public: 268 CSpawnIoRedirect(); 269 // NOTE: there is no real implementation of I/O redirection yet. 270 protected: 271 private: 272 }; CSpawnIoRedirect()273 CSpawnIoRedirect::CSpawnIoRedirect() 274 { 275 } 276 typedef enum { 277 ESpawnNone = 0x00000000, 278 ESpawnWait = 0x00000001 279 } TSpawnFlag; symbian_spawn(const TDesC & aFilename,const TDesC & aCommand,const TSpawnFlag aFlag,const CSpawnIoRedirect & aIoRedirect)280 static int symbian_spawn(const TDesC& aFilename, 281 const TDesC& aCommand, 282 const TSpawnFlag aFlag, 283 const CSpawnIoRedirect& aIoRedirect) { 284 TInt error = KErrNone; 285 #ifdef __WINS__ 286 const TInt KStackSize = 0x1000; 287 const TInt KHeapMin = 0x1000; 288 const TInt KHeapMax = 0x100000; 289 RThread proc; 290 RLibrary lib; 291 HBufC* command = aCommand.Alloc(); 292 error = lib.Load(aFilename); 293 if (error == KErrNone) { 294 TThreadFunction func = (TThreadFunction)(lib.Lookup(1)); 295 if (func) 296 error = proc.Create(aFilename, 297 func, 298 KStackSize, 299 #ifdef __SERIES60_3X__ 300 KHeapMin, 301 KHeapMax, 302 (TAny*)command, 303 #else 304 (TAny*)command, 305 &lib, 306 RThread().Heap(), 307 KHeapMin, 308 KHeapMax, 309 #endif 310 EOwnerProcess); 311 else 312 error = KErrNotFound; 313 lib.Close(); 314 } 315 else 316 delete command; 317 #else 318 RProcess proc; 319 error = proc.Create(aFilename, aCommand); 320 #endif 321 if (error == KErrNone) { 322 if ((TInt)aFlag & (TInt)ESpawnWait) { 323 CProcessWait* w = new CProcessWait(); 324 if (w) { 325 error = w->Wait(proc); 326 delete w; 327 } else 328 error = KErrNoMemory; 329 } else 330 proc.Resume(); 331 proc.Close(); 332 } 333 return error; 334 } symbian_spawner(const char * command,TSpawnFlag aFlags)335 static int symbian_spawner(const char *command, TSpawnFlag aFlags) 336 { 337 TBuf<KMaxFileName> aFilename; 338 TBuf<KMaxFileName> aCommand; 339 TSpawnFlag aSpawnFlags = ESpawnWait; 340 CSpawnIoRedirect iord; 341 char *p = (char*)command; 342 343 // The recognized syntax is: "cmd [args] [&]". Since one 344 // cannot pass more than (an argv[0] and) an argv[1] to a 345 // Symbian process anyway, not much is done to the cmd or 346 // the args, only backslash quoting. 347 348 // Strip leading whitespace. 349 while (*p && isspace(*p)) p++; 350 if (*p) { 351 // Build argv[0]. 352 while (*p && !isspace(*p) && *p != '&') { 353 if (*p == '\\') { 354 if (p[1]) { 355 aFilename.Append(p[1]); 356 p++; 357 } 358 359 } 360 else 361 aFilename.Append(*p); 362 p++; 363 } 364 365 if (*p) { 366 // Skip whitespace between argv[0] and argv[1]. 367 while(*p && isspace(*p)) p++; 368 // Build argv[1]. 369 if (*p) { 370 char *a = p; 371 char *b = p + 1; 372 373 while (*b) b++; 374 if (isspace(b[-1])) { 375 b--; 376 while (b > a && isspace(*b)) b--; 377 b++; 378 } 379 if (b > a && b[-1] == '&') { 380 // Parse backgrounding in any case, 381 // but turn it off only if wanted. 382 if ((aFlags & ESpawnWait)) 383 aSpawnFlags = 384 (TSpawnFlag) (aSpawnFlags & ~ESpawnWait); 385 b--; 386 if (isspace(b[-1])) { 387 b--; 388 while (b > a && isspace(*b)) b--; 389 b++; 390 } 391 } 392 for (p = a; p < b; p++) { 393 if (*p == '\\') { 394 if (p[1]) 395 aCommand.Append(p[1]); 396 p++; 397 } 398 else 399 aCommand.Append(*p); 400 } 401 } 402 // NOTE: I/O redirection is not yet done. 403 // Implementing that may require a separate server. 404 } 405 } 406 int spawned = symbian_spawn(aFilename, aCommand, aSpawnFlags, iord); 407 return spawned == KErrNone ? 0 : -1; 408 } symbian_do_spawn(const char * command)409 EXPORT_C int symbian_do_spawn(const char *command) 410 { 411 return symbian_spawner(command, ESpawnWait); 412 } symbian_do_spawn_nowait(const char * command)413 EXPORT_C int symbian_do_spawn_nowait(const char *command) 414 { 415 return symbian_spawner(command, ESpawnNone); 416 } symbian_do_aspawn(void * vreally,void * vmark,void * sp)417 EXPORT_C int symbian_do_aspawn(void* vreally, void* vmark, void* sp) 418 { 419 return -1; 420 } 421 } 422 423