1 /* Copyright (c) 2004-2005 Nokia. All rights reserved. */
3 /* The PerlApp application is licensed under the same terms as Perl itself.
4 * Note that this PerlApp is for Symbian/Series 60/80 smartphones and it has
5 * nothing whatsoever to do with the ActiveState PerlApp. */
11 # include <aknnotewrappers.h>
12 # include <AknCommonDialogs.h>
13 # ifndef __SERIES60_1X__
14 # include <CAknFileSelectionDialog.h>
16 #endif /* #ifdef __SERIES60__ */
20 # include <cknflash.h>
21 # include <ckndgopn.h>
22 #endif /* #ifdef __SERIES80__ */
37 #include "PerlApp.hrh"
39 #include "PerlApp.rsg"
41 #endif //#ifndef PerlMin
47 const TUid KPerlAppUid = {
55 _LIT(KDefaultScript, "default.pl");
57 // This is like the Symbian _LIT() but without the embedded L prefix,
58 // which enables using #defined constants (which need to carry their
61 # define _LIT_NO_L(n, s) static const TLitC<sizeof(s)/2> n={sizeof(s)/2-1,s}
62 #endif // #ifndef _LIT_NO_L
65 _LIT_NO_L(KAppName, PerlMinName);
67 _LIT(KAppName, "PerlApp");
72 _LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR);
74 "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d");
75 _LIT(KCopyrightFormat,
76 "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005");
77 _LIT(KInboxPrefix, "\\System\\Mail\\");
78 _LIT(KScriptPrefix, "\\Perl\\");
80 _LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h
82 typedef TBuf<256> TMessageBuffer;
83 typedef TBuf8<256> TPeekBuffer;
84 typedef TBuf8<256> TFileName8;
86 #endif // #ifndef PerlMin
88 // Usage: DEBUG_PRINTF((_L("%S"), &aStr))
90 #define DEBUG_PRINTF(s) {TMessageBuffer message; message.Format s; YesNoDialogL(message);}
93 static void DoRunScriptL(TFileName aScriptName);
95 TUid CPerlAppApplication::AppDllUid() const
102 EPerlAppCommandUnknown = 1
105 void Panic(TPerlAppPanic aReason)
107 User::Panic(KAppName, aReason);
110 void CPerlAppUi::ConstructL()
113 iAppView = CPerlAppView::NewL(ClientRect());
114 AddToStackL(iAppView);
116 CEikonEnv::Static()->DisableExitChecks(ETrue); // Symbian FAQ-0577.
119 CPerlAppUi::~CPerlAppUi()
122 iEikonEnv->RemoveFromStack(iAppView);
130 if (iDoorObserver) // Otherwise the embedding application waits forever.
131 iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty);
138 static TBool DlgOk(CAknNoteDialog* dlg)
140 return dlg && dlg->RunDlgLD() == EAknSoftkeyOk;
143 #endif /* #ifdef __SERIES60__ */
145 static TBool OkCancelDialogL(TDesC& aMessage)
148 CAknNoteDialog* dlg =
149 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
150 dlg->PrepareLC(R_OK_CANCEL_DIALOG);
151 dlg->SetTextL(aMessage);
153 #endif /* #ifdef __SERIES60__ */
155 return CCknFlashingDialog::RunDlgLD(_L("OK/Cancel"), aMessage, NULL,
156 CCknFlashingDialog::EShort,
158 #endif /* #ifdef __SERIES80__ */
161 static TBool YesNoDialogL(TDesC& aMessage)
164 CAknNoteDialog* dlg =
165 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
166 dlg->PrepareLC(R_YES_NO_DIALOG);
167 dlg->SetTextL(aMessage);
169 #endif /* #ifdef __SERIES60__ */
171 return CCknFlashingDialog::RunDlgLD(_L("Yes/No"), aMessage, NULL,
172 CCknFlashingDialog::EShort,
174 #endif /* #ifdef __SERIES80__ */
177 static TInt InformationNoteL(TDesC& aMessage)
180 CAknInformationNote* note = new (ELeave) CAknInformationNote;
181 return note->ExecuteLD(aMessage);
182 #endif /* #ifdef __SERIES60__ */
184 return CCknFlashingDialog::RunDlgLD(_L("Info"), aMessage, NULL,
185 CCknFlashingDialog::ENormal,
187 #endif /* #ifdef __SERIES80__ */
190 static TInt ConfirmationNoteL(TDesC& aMessage)
193 CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote;
194 return note->ExecuteLD(aMessage);
195 #endif /* #ifdef __SERIES60__ */
197 return CCknFlashingDialog::RunDlgLD(_L("Confirmation"), aMessage, NULL,
198 CCknFlashingDialog::ENormal,
200 #endif /* #ifdef __SERIES80__ */
203 static TInt WarningNoteL(TDesC& aMessage)
206 CAknWarningNote* note = new (ELeave) CAknWarningNote;
207 return note->ExecuteLD(aMessage);
208 #endif /* #ifdef __SERIES60__ */
210 CEikonEnv::Static()->AlertWin(aMessage);
212 #endif /* #ifdef __SERIES80__ */
215 static TInt TextQueryDialogL(const TDesC& aPrompt, TDes& aData, const TInt aMaxLength)
218 CAknTextQueryDialog* dlg =
219 new (ELeave) CAknTextQueryDialog(aData);
220 dlg->SetPromptL(aPrompt);
221 dlg->SetMaxLength(aMaxLength);
222 return dlg->ExecuteLD(R_TEXT_QUERY_DIALOG);
223 #endif /* #ifdef __SERIES60__ */
230 // The isXXX() come from the Perl headers.
231 #define FILENAME_IS_ABSOLUTE(n) \
232 (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\')
234 static TBool IsInPerl(TFileName aFileName)
236 TInt offset = aFileName.FindF(KScriptPrefix);
237 return ((offset == 0 && // \foo
238 aFileName[0] == '\\')
240 (offset == 2 && // x:\foo
241 FILENAME_IS_ABSOLUTE(aFileName)));
244 static TBool IsInInbox(TFileName aFileName)
246 TInt offset = aFileName.FindF(KInboxPrefix);
247 return ((offset == 0 && // \foo
248 aFileName[0] == '\\')
250 (offset == 2 && // x:\foo
251 FILENAME_IS_ABSOLUTE(aFileName)));
254 static TBool IsPerlModule(TParsePtrC aParsed)
256 return aParsed.Ext().CompareF(_L(".pm")) == 0;
259 static TBool IsPerlScript(TParsePtrC aParsed)
261 return aParsed.Ext().CompareF(_L(".pl")) == 0;
264 static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst)
266 TBool proceed = ETrue;
267 TMessageBuffer message;
269 message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst);
270 if (OkCancelDialogL(message)) {
271 message.Format(_L("Install as %S?"), &aDst);
272 if (OkCancelDialogL(message)) {
273 if (BaflUtils::FileExists(aFs, aDst)) {
274 message.Format(_L("Replace old %S?"), &aDst);
275 if (!OkCancelDialogL(message))
280 TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst);
281 if (err == KErrNone) {
282 message.Format(_L("Installed %S"), &aDst);
283 ConfirmationNoteL(message);
286 message.Format(_L("Failure %d installing %S"), err, &aDst);
287 WarningNoteL(message);
294 static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn)
297 TInt m = aFn.MaxLength();
298 TInt n = aPeekBuffer.Length();
303 // The following is a little regular expression
304 // engine that matches Perl package names.
305 if (j < n && isSPACE(aPeekBuffer[j])) {
306 while (j < n && isSPACE(aPeekBuffer[j])) j++;
307 if (j < n && isALPHA(aPeekBuffer[j])) {
308 while (j < n && isALNUM(aPeekBuffer[j])) {
310 isALNUM(aPeekBuffer[j]) &&
312 aFn[i++] = aPeekBuffer[j++];
314 aPeekBuffer[j ] == ':' &&
315 aPeekBuffer[j + 1] == ':' &&
320 isALPHA(aPeekBuffer[j])) {
322 isALNUM(aPeekBuffer[j]) &&
324 aFn[i++] = aPeekBuffer[j++];
328 while (j < n && isSPACE(aPeekBuffer[j])) j++;
329 if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) {
331 aFn.Append(_L(".pm"));
339 static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive)
341 TInt offset = aPeekBuffer.Find(_L8("package"));
342 if (offset != KErrNotFound) {
343 const TInt KPackageLen = 7;
346 if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q))
350 p.Copy(aDrive.Drive());
351 p.Append(KModulePrefix);
354 if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) {
357 for (j = 0; j < p.Length(); j++)
360 for (j = 0; j < q.Length(); j++)
369 static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer)
371 return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 &&
372 aPeekBuffer.Find(_L8("perl")) != KErrNotFound;
375 static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs)
378 TPtrC drive = aDrive.Drive();
379 TPtrC namext = aFile.NameAndExt();
381 aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext);
382 if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) {
384 if (IsPerlModule(aDst))
385 GuessPerlModule(aDst, aPeekBuffer, aDrive);
387 if (aDst.Length() > 0) {
388 CopyFromInboxL(aFs, aSrc, aDst);
395 static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer)
397 TBool isModule = EFalse;
399 if (IsInPerl(aScriptName) &&
400 (IsPerlScript(aScriptName) ||
401 (isModule = IsPerlModule(aScriptName)) ||
402 LooksLikePerlL(aPeekBuffer))) {
403 TMessageBuffer message;
406 message.Format(_L("Really run module %S?"), &aScriptName);
408 message.Format(_L("Run %S?"), &aScriptName);
409 if (YesNoDialogL(message))
410 DoRunScriptL(aScriptName);
418 void CPerlAppUi::InstallOrRunL(const TFileName& aFileName)
422 TMessageBuffer message;
424 aFile.Set(aFileName, NULL, NULL);
425 if (FILENAME_IS_ABSOLUTE(aFileName)) {
426 aDrive.Set(aFileName, NULL, NULL);
429 CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
430 aDrive.Set(appName, NULL, NULL);
433 iFs = &CEikonEnv::Static()->FsSession();
435 TInt err = f.Open(*iFs, aFileName, EFileRead);
436 if (err == KErrNone) {
437 TPeekBuffer aPeekBuffer;
438 err = f.Read(aPeekBuffer);
439 f.Close(); // Release quickly.
440 if (err == KErrNone) {
441 if (!(IsInInbox(aFileName) ?
442 InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) :
443 RunStuffL(aFileName, aPeekBuffer))) {
444 message.Format(_L("Failed for file %S"), &aFileName);
445 WarningNoteL(message);
448 message.Format(_L("Error %d reading %S"), err, &aFileName);
449 WarningNoteL(message);
452 message.Format(_L("Error %d opening %S"), err, &aFileName);
453 WarningNoteL(message);
456 delete CEikonEnv::Static()->EikAppUi();
461 #endif // #ifndef PerlMin
463 static void DoRunScriptL(TFileName aScriptName)
465 CPerlBase* perl = CPerlBase::NewInterpreterLC();
466 TRAPD(error, perl->RunScriptL(aScriptName));
468 if (error != KErrNone) {
469 TMessageBuffer message;
470 message.Format(_L("Error %d"), error);
471 YesNoDialogL(message);
473 #endif // #ifndef PerlMin
474 CleanupStack::PopAndDestroy(perl);
479 void CPerlAppUi::OpenFileL(const TDesC& aFileName)
481 InstallOrRunL(aFileName);
485 #endif // #ifndef PerlMin
487 TBool CPerlAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */)
489 if (aCommand == EApaCommandRun) {
490 TFileName appName = Application()->AppFullName();
492 p.Set(KDefaultScript, &appName, NULL);
496 if (aFs.Entry(p.FullName(), aEntry) == KErrNone) {
497 DoRunScriptL(p.FullName());
501 return aCommand == EApaCommandOpen ? ETrue : EFalse;
506 void CPerlAppUi::SetFs(const RFs& aFs)
511 #endif // #ifndef PerlMin
513 static void DoHandleCommandL(TInt aCommand) {
515 TMessageBuffer message;
516 #endif // #ifndef PerlMin
521 case EPerlAppCommandAbout:
523 message.Format(KAboutFormat,
527 PERL_SYMBIANPORT_MAJOR,
528 PERL_SYMBIANPORT_MINOR,
529 PERL_SYMBIANPORT_PATCH,
531 PERL_SYMBIANSDK_MAJOR,
532 PERL_SYMBIANSDK_MINOR
534 InformationNoteL(message);
537 case EPerlAppCommandTime:
539 CPerlBase* perl = CPerlBase::NewInterpreterLC();
540 const char *const argv[] =
542 "print 'Running in ', $^O, \"\\n\", scalar localtime" };
543 perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0);
544 CleanupStack::PopAndDestroy(perl);
547 case EPerlAppCommandRunFile:
549 TFileName aScriptUtf16;
551 if (AknCommonDialogs::RunSelectDlgLD(aScriptUtf16,
552 R_MEMORY_SELECTION_DIALOG))
553 DoRunScriptL(aScriptUtf16);
554 #endif /* #ifdef __SERIES60__ */
556 aScriptUtf16.Copy(_L("C:\\"));
557 if (CCknOpenFileDialog::RunDlgLD(aScriptUtf16,
558 CCknOpenFileDialog::EShowSystemFilesAndFolders |
559 CCknOpenFileDialog::EShowHiddenFilesAndFolders |
560 CCknOpenFileDialog::EShowAllDrives |
561 CCknOpenFileDialog::EShowExtendedView |
562 CCknOpenFileDialog::EShowNoFilesText) {
563 /* TODO: despite all the above flags still does not seem
564 * to allow navigating outside the default directory. */
568 if (aFs.Entry(aScriptUtf16, aEntry) == KErrNone)
569 DoRunScriptL(aScriptUtf16);
570 /* else show error message? */
572 #endif /* #ifdef __SERIES80__ */
575 case EPerlAppCommandOneLiner:
577 _LIT(prompt, "Oneliner:");
579 STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
580 if (TextQueryDialogL(prompt,
582 KPerlAppOneLinerSize)) {
583 const TUint KPerlAppUtf8Multi = 3;
584 TBuf8<KPerlAppUtf8Multi * KPerlAppOneLinerSize> utf8;
586 CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8, cAppUi->iOneLiner);
587 CPerlBase* perl = CPerlBase::NewInterpreterLC();
589 char **argv = (char**) malloc(argc * sizeof(char *));
590 User::LeaveIfNull(argv);
592 TCleanupItem argvCleanupItem = TCleanupItem(free, argv);
593 CleanupStack::PushL(argvCleanupItem);
594 argv[0] = (char *) "perl";
595 argv[1] = (char *) "-le";
596 argv[2] = (char *) utf8.PtrZ();
597 perl->ParseAndRun(argc, argv);
598 CleanupStack::PopAndDestroy(2, perl);
602 case EPerlAppCommandCopyright:
604 message.Format(KCopyrightFormat);
605 InformationNoteL(message);
608 case EPerlAppCommandAboutCopyright:
612 m1.Format(KAboutFormat,
616 PERL_SYMBIANPORT_MAJOR,
617 PERL_SYMBIANPORT_MINOR,
618 PERL_SYMBIANPORT_PATCH,
620 PERL_SYMBIANSDK_MAJOR,
621 PERL_SYMBIANSDK_MINOR
623 InformationNoteL(message);
624 m2.Format(KCopyrightFormat);
625 message.Format(_L("%S %S"), &m1, &m2);
626 InformationNoteL(message);
629 #endif // #ifndef PerlMin
631 Panic(EPerlAppCommandUnknown);
637 void CPerlAppUi::HandleCommandL(TInt aCommand)
642 case EAknSoftkeyExit:
646 DoHandleCommandL(aCommand);
651 #endif /* #ifdef __SERIES60__ */
655 void CPerlAppView::HandleCommandL(TInt aCommand) {
656 DoHandleCommandL(aCommand);
659 void CPerlAppUi::HandleCommandL(TInt aCommand) {
666 iAppView->HandleCommandL(aCommand);
671 #endif /* #ifdef __SERIES80__ */
673 CPerlAppView* CPerlAppView::NewL(const TRect& aRect)
675 CPerlAppView* self = CPerlAppView::NewLC(aRect);
676 CleanupStack::Pop(self);
680 CPerlAppView* CPerlAppView::NewLC(const TRect& aRect)
682 CPerlAppView* self = new (ELeave) CPerlAppView;
683 CleanupStack::PushL(self);
684 self->ConstructL(aRect);
688 void CPerlAppView::ConstructL(const TRect& aRect)
695 CPerlAppView::~CPerlAppView()
699 void CPerlAppView::Draw(const TRect& /*aRect*/) const
701 CWindowGc& gc = SystemGc();
706 CApaDocument* CPerlAppApplication::CreateDocumentL()
708 CPerlAppDocument* document = new (ELeave) CPerlAppDocument(*this);
712 CEikAppUi* CPerlAppDocument::CreateAppUiL()
714 CPerlAppUi* appui = new (ELeave) CPerlAppUi();
721 CFileStore* CPerlAppDocument::OpenFileL(TBool aDoOpen, const TDesC& aFileName, RFs& aFs)
724 STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
727 appui->OpenFileL(aFileName);
731 #endif // #ifndef PerlMin
733 EXPORT_C CApaApplication* NewApplication()
735 return new CPerlAppApplication;
738 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)