1 /* Copyright (c) 2004-2005 Nokia. All rights reserved. */
3 /* The PerlApp application is licensed under the same terms as Perl itself.
5 * Note that this PerlApp is for Symbian/Series 60/80/UIQ smartphones
6 * and it has nothing whatsoever to do with the ActiveState PerlApp. */
21 #ifndef PerlAppMinimal
23 #include "PerlApp.hrh"
25 #endif //#ifndef PerlAppMinimal
27 #define PERL_GLOBAL_STRUCT
28 #define PERL_GLOBAL_STRUCT_PRIVATE
37 #define symbian_get_vars() Dll::Tls() // Not visible from perlXYZ.lib?
39 const TUid KPerlAppUid = {
40 #ifdef PerlAppMinimalUid
47 _LIT(KDefaultScript, "default.pl");
49 #ifdef PerlAppMinimalName
50 _LIT_NO_L(KAppName, PerlAppMinimalName);
52 _LIT(KAppName, "PerlApp");
55 #ifndef PerlAppMinimal
57 _LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR);
59 "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d");
60 _LIT(KCopyrightFormat,
61 "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005");
62 _LIT(KInboxPrefix, "\\System\\Mail\\");
63 _LIT(KScriptPrefix, "\\Perl\\");
65 _LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h
67 typedef TBuf<256> TMessageBuffer;
68 typedef TBuf8<256> TPeekBuffer;
69 typedef TBuf8<256> TFileName8;
71 #endif // #ifndef PerlAppMinimal
73 static void DoRunScriptL(TFileName aScriptName);
75 TUid CPerlAppApplication::AppDllUid() const
82 EPerlAppCommandUnknown = 1
85 void Panic(TPerlAppPanic aReason)
87 User::Panic(KAppName, aReason);
90 #ifndef PerlAppMinimal
92 // The isXXX() come from the Perl headers.
93 #define FILENAME_IS_ABSOLUTE(n) \
94 (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\')
96 static TBool IsInPerl(TFileName aFileName)
98 TInt offset = aFileName.FindF(KScriptPrefix);
99 return ((offset == 0 && // \foo
100 aFileName[0] == '\\')
102 (offset == 2 && // x:\foo
103 FILENAME_IS_ABSOLUTE(aFileName)));
106 static TBool IsInInbox(TFileName aFileName)
108 TInt offset = aFileName.FindF(KInboxPrefix);
109 return ((offset == 0 && // \foo
110 aFileName[0] == '\\')
112 (offset == 2 && // x:\foo
113 FILENAME_IS_ABSOLUTE(aFileName)));
116 static TBool IsPerlModule(TParsePtrC aParsed)
118 return aParsed.Ext().CompareF(_L(".pm")) == 0;
121 static TBool IsPerlScript(TParsePtrC aParsed)
123 return aParsed.Ext().CompareF(_L(".pl")) == 0;
126 static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst)
128 TBool proceed = ETrue;
129 TMessageBuffer message;
131 message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst);
132 if (CPerlUi::OkCancelDialogL(message)) {
133 message.Format(_L("Install as %S?"), &aDst);
134 if (CPerlUi::OkCancelDialogL(message)) {
135 if (BaflUtils::FileExists(aFs, aDst)) {
136 message.Format(_L("Replace old %S?"), &aDst);
137 if (!CPerlUi::OkCancelDialogL(message))
142 TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst);
143 if (err == KErrNone) {
144 message.Format(_L("Installed %S"), &aDst);
145 CPerlUi::InformationNoteL(message);
148 message.Format(_L("Failure %d installing %S"), err, &aDst);
149 CPerlUi::WarningNoteL(message);
156 static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn)
159 TInt m = aFn.MaxLength();
160 TInt n = aPeekBuffer.Length();
165 // The following is a little regular expression
166 // engine that matches Perl package names.
167 if (j < n && isSPACE(aPeekBuffer[j])) {
168 while (j < n && isSPACE(aPeekBuffer[j])) j++;
169 if (j < n && isALPHA(aPeekBuffer[j])) {
170 while (j < n && isALNUM(aPeekBuffer[j])) {
172 isALNUM(aPeekBuffer[j]) &&
174 aFn[i++] = aPeekBuffer[j++];
176 aPeekBuffer[j ] == ':' &&
177 aPeekBuffer[j + 1] == ':' &&
182 isALPHA(aPeekBuffer[j])) {
184 isALNUM(aPeekBuffer[j]) &&
186 aFn[i++] = aPeekBuffer[j++];
190 while (j < n && isSPACE(aPeekBuffer[j])) j++;
191 if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) {
193 aFn.Append(_L(".pm"));
201 static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive)
203 TInt offset = aPeekBuffer.Find(_L8("package"));
204 if (offset != KErrNotFound) {
205 const TInt KPackageLen = 7;
208 if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q))
212 p.Copy(aDrive.Drive());
213 p.Append(KModulePrefix);
216 if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) {
219 for (j = 0; j < p.Length(); j++)
222 for (j = 0; j < q.Length(); j++)
231 static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer)
233 return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 &&
234 aPeekBuffer.Find(_L8("perl")) != KErrNotFound;
237 static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs)
240 TPtrC drive = aDrive.Drive();
241 TPtrC namext = aFile.NameAndExt();
243 aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext);
244 if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) {
246 if (IsPerlModule(aDst))
247 GuessPerlModule(aDst, aPeekBuffer, aDrive);
249 if (aDst.Length() > 0) {
250 CopyFromInboxL(aFs, aSrc, aDst);
257 static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer)
259 TBool isModule = EFalse;
261 if (IsInPerl(aScriptName) &&
262 (IsPerlScript(aScriptName) ||
263 (isModule = IsPerlModule(aScriptName)) ||
264 LooksLikePerlL(aPeekBuffer))) {
265 TMessageBuffer message;
268 message.Format(_L("Really run module %S?"), &aScriptName);
270 message.Format(_L("Run %S?"), &aScriptName);
271 if (CPerlUi::YesNoDialogL(message))
272 DoRunScriptL(aScriptName);
279 void CPerlAppAppUi::InstallOrRunL(const TFileName& aFileName)
283 TMessageBuffer message;
285 aFile.Set(aFileName, NULL, NULL);
286 if (FILENAME_IS_ABSOLUTE(aFileName)) {
287 aDrive.Set(aFileName, NULL, NULL);
290 CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
291 aDrive.Set(appName, NULL, NULL);
294 iFs = &CEikonEnv::Static()->FsSession();
296 TInt err = f.Open(*iFs, aFileName, EFileRead);
297 if (err == KErrNone) {
298 TPeekBuffer aPeekBuffer;
299 err = f.Read(aPeekBuffer);
300 f.Close(); // Release quickly.
301 if (err == KErrNone) {
302 if (!(IsInInbox(aFileName) ?
303 InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) :
304 RunStuffL(aFileName, aPeekBuffer))) {
305 message.Format(_L("Failed for file %S"), &aFileName);
306 CPerlUi::WarningNoteL(message);
309 message.Format(_L("Error %d reading %S"), err, &aFileName);
310 CPerlUi::WarningNoteL(message);
313 message.Format(_L("Error %d opening %S"), err, &aFileName);
314 CPerlUi::WarningNoteL(message);
317 delete CEikonEnv::Static()->EikAppUi();
322 #endif /* #ifndef PerlAppMinimal */
324 CPerlAppAppUi::~CPerlAppAppUi()
327 iEikonEnv->RemoveFromStack(iAppView);
335 if (iDoorObserver) // Otherwise the embedding application waits forever.
336 iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty);
339 static void DoRunScriptL(TFileName aScriptName)
341 CPerlBase* perl = CPerlBase::NewInterpreterLC();
342 TRAPD(error, perl->RunScriptL(aScriptName));
343 #ifndef PerlAppMinimal
344 if (error != KErrNone) {
345 TMessageBuffer message;
346 message.Format(_L("Error %d"), error);
347 CPerlUi::YesNoDialogL(message);
349 #endif // #ifndef PerlAppMinimal
350 CleanupStack::PopAndDestroy(perl);
353 #ifndef PerlAppMinimal
355 void CPerlAppAppUi::OpenFileL(const TDesC& aFileName)
357 InstallOrRunL(aFileName);
361 #endif // #ifndef PerlAppMinimal
363 TBool CPerlAppAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */)
365 if (aCommand == EApaCommandRun) {
366 TFileName appName = Application()->AppFullName();
368 p.Set(KDefaultScript, &appName, NULL);
372 if (aFs.Entry(p.FullName(), aEntry) == KErrNone) {
373 DoRunScriptL(p.FullName());
377 return aCommand == EApaCommandOpen ? ETrue : EFalse;
380 #ifndef PerlAppMinimal
382 void CPerlAppAppUi::SetFs(const RFs& aFs)
387 #endif // #ifndef PerlAppMinimal
389 void CPerlAppAppUi::DoHandleCommandL(TInt aCommand) {
390 #ifndef PerlAppMinimal
391 TMessageBuffer message;
392 #endif // #ifndef PerlAppMinimal
396 #ifndef PerlAppMinimal
397 case EPerlAppCommandAbout:
399 message.Format(KAboutFormat,
403 PERL_SYMBIANPORT_MAJOR,
404 PERL_SYMBIANPORT_MINOR,
405 PERL_SYMBIANPORT_PATCH,
407 PERL_SYMBIANSDK_MAJOR,
408 PERL_SYMBIANSDK_MINOR
410 CPerlUi::InformationNoteL(message);
413 case EPerlAppCommandTime:
415 CPerlBase* perl = CPerlBase::NewInterpreterLC();
416 const char *const argv[] =
418 "print 'Running in ', $^O, \"\\n\", scalar localtime" };
419 perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0);
420 CleanupStack::PopAndDestroy(perl);
424 case EPerlAppCommandRunFile:
426 TFileName aScriptUtf16;
427 aScriptUtf16.Copy(_L("C:\\"));
428 if (CPerlUi::FileQueryDialogL(aScriptUtf16))
429 DoRunScriptL(aScriptUtf16);
433 case EPerlAppCommandOneLiner:
436 _LIT(prompt, "Oneliner:");
437 #endif /* #ifdef __SERIES60__ */
438 #if defined(__SERIES80__) || defined(__UIQ__)
439 _LIT(prompt, "Code:"); // The title has "Oneliner" already.
440 #endif /* #if defined(__SERIES80__) || defined(__UIQ__) */
441 CPerlAppAppUi* cAppUi =
442 static_cast<CPerlAppAppUi*>(CEikonEnv::Static()->EikAppUi());
443 if (CPerlUi::TextQueryDialogL(_L("Oneliner"),
446 KPerlUiOneLinerSize)) {
447 const TUint KPerlUiUtf8Multi = 3; // Expansion multiplier.
448 TBuf8<KPerlUiUtf8Multi * KPerlUiOneLinerSize> utf8;
450 CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8,
452 CPerlBase* perl = CPerlBase::NewInterpreterLC();
454 char **argv = (char**) malloc(argc * sizeof(char *));
455 User::LeaveIfNull(argv);
457 TCleanupItem argvCleanupItem = TCleanupItem(free, argv);
458 CleanupStack::PushL(argvCleanupItem);
459 argv[0] = (char *) "perl";
460 argv[1] = (char *) "-le";
461 argv[2] = (char *) utf8.PtrZ();
462 perl->ParseAndRun(argc, argv);
463 CleanupStack::PopAndDestroy(2, perl);
467 case EPerlAppCommandCopyright:
469 message.Format(KCopyrightFormat);
470 CPerlUi::InformationNoteL(message);
473 case EPerlAppCommandAboutCopyright:
477 m1.Format(KAboutFormat,
481 PERL_SYMBIANPORT_MAJOR,
482 PERL_SYMBIANPORT_MINOR,
483 PERL_SYMBIANPORT_PATCH,
485 PERL_SYMBIANSDK_MAJOR,
486 PERL_SYMBIANSDK_MINOR
488 CPerlUi::InformationNoteL(m1);
489 User::After((TTimeIntervalMicroSeconds32) (1000*1000)); // 1 sec.
490 m2.Format(KCopyrightFormat);
491 CPerlUi::InformationNoteL(m2);
494 #endif // #ifndef PerlAppMinimal
496 Panic(EPerlAppCommandUnknown);
500 CApaDocument* CPerlAppApplication::CreateDocumentL()
502 CPerlAppDocument* cDoc = new (ELeave) CPerlAppDocument(*this);
506 CEikAppUi* CPerlAppDocument::CreateAppUiL()
508 CPerlAppAppUi* cAppUi = new (ELeave) CPerlAppAppUi();
513 #ifndef PerlAppMinimal
515 CFileStore* CPerlAppDocument::OpenFileL(TBool aDoOpen, const TDesC& aFileName, RFs& aFs)
517 CPerlAppAppUi* cAppUi =
518 static_cast<CPerlAppAppUi*>(CEikonEnv::Static()->EikAppUi());
521 cAppUi->OpenFileL(aFileName);
525 #endif // #ifndef PerlAppMinimal
527 EXPORT_C CApaApplication* NewApplication()
529 return new CPerlAppApplication;
532 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)