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 # include <ckndgfob.h>
23 # include <eiklabel.h>
25 #endif /* #ifdef __SERIES80__ */
38 #ifndef PerlAppMinimal
40 #include "PerlApp.hrh"
42 #include "PerlApp.rsg"
46 #endif /* #ifdef __SERIES80__ */
48 #endif //#ifndef PerlAppMinimal
54 const TUid KPerlAppUid = {
55 #ifdef PerlAppMinimalUid
62 _LIT(KDefaultScript, "default.pl");
64 // This is like the Symbian _LIT() but without the embedded L prefix,
65 // which enables using #defined constants (which need to carry their
68 # define _LIT_NO_L(n, s) static const TLitC<sizeof(s)/2> n={sizeof(s)/2-1,s}
69 #endif // #ifndef _LIT_NO_L
71 #ifdef PerlAppMinimalName
72 _LIT_NO_L(KAppName, PerlAppMinimalName);
74 _LIT(KAppName, "PerlApp");
77 #ifndef PerlAppMinimal
79 _LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR);
81 "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d");
82 _LIT(KCopyrightFormat,
83 "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005");
84 _LIT(KInboxPrefix, "\\System\\Mail\\");
85 _LIT(KScriptPrefix, "\\Perl\\");
87 _LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h
89 typedef TBuf<256> TMessageBuffer;
90 typedef TBuf8<256> TPeekBuffer;
91 typedef TBuf8<256> TFileName8;
93 #endif // #ifndef PerlAppMinimal
95 // Usage: DEBUG_PRINTF((_L("%S"), &aStr))
97 #define DEBUG_PRINTF(s) {TMessageBuffer message; message.Format s; YesNoDialogL(message);}
100 static void DoRunScriptL(TFileName aScriptName);
102 TUid CPerlAppApplication::AppDllUid() const
109 EPerlAppCommandUnknown = 1
112 void Panic(TPerlAppPanic aReason)
114 User::Panic(KAppName, aReason);
117 void CPerlAppUi::ConstructL()
120 iAppView = CPerlAppView::NewL(ClientRect());
121 AddToStackL(iAppView);
123 CEikonEnv::Static()->DisableExitChecks(ETrue); // Symbian FAQ-0577.
126 CPerlAppUi::~CPerlAppUi()
129 iEikonEnv->RemoveFromStack(iAppView);
137 if (iDoorObserver) // Otherwise the embedding application waits forever.
138 iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty);
141 #ifndef PerlAppMinimal
145 static TBool DlgOk(CAknNoteDialog* dlg)
147 return dlg && dlg->RunDlgLD() == EAknSoftkeyOk;
150 #endif /* #ifdef __SERIES60__ */
152 static TBool OkCancelDialogL(TDesC& aMessage)
155 CAknNoteDialog* dlg =
156 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
157 dlg->PrepareLC(R_OK_CANCEL_DIALOG);
158 dlg->SetTextL(aMessage);
160 #endif /* #ifdef __SERIES60__ */
162 return CCknConfirmationDialog::RunDlgWithDefaultIconLD(aMessage, R_EIK_BUTTONS_CANCEL_OK);
163 #endif /* #ifdef __SERIES80__ */
166 static TBool YesNoDialogL(TDesC& aMessage)
169 CAknNoteDialog* dlg =
170 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
171 dlg->PrepareLC(R_YES_NO_DIALOG);
172 dlg->SetTextL(aMessage);
174 #endif /* #ifdef __SERIES60__ */
176 return CCknConfirmationDialog::RunDlgWithDefaultIconLD(aMessage, R_EIK_BUTTONS_NO_YES);
177 #endif /* #ifdef __SERIES80__ */
180 static void InformationNoteL(TDesC& aMessage)
183 CAknInformationNote* note = new (ELeave) CAknInformationNote;
184 note->ExecuteLD(aMessage);
185 #endif /* #ifdef __SERIES60__ */
187 CEikonEnv::Static()->InfoMsg(aMessage);
188 #endif /* #ifdef __SERIES80__ */
191 static TInt WarningNoteL(TDesC& aMessage)
194 CAknWarningNote* note = new (ELeave) CAknWarningNote;
195 return note->ExecuteLD(aMessage);
196 #endif /* #ifdef __SERIES60__ */
198 CEikonEnv::Static()->AlertWin(aMessage);
200 #endif /* #ifdef __SERIES80__ */
205 CPerlAppTextQueryDialog::CPerlAppTextQueryDialog(HBufC*& aBuffer) :
210 TBool CPerlAppTextQueryDialog::OkToExitL(TInt /* aKeycode */)
212 iData = static_cast<CEikEdwin*>(Control(EPerlAppTextQueryInputField))->GetTextInHBufL();
216 void CPerlAppTextQueryDialog::PreLayoutDynInitL()
219 CEikLabel* promptLabel = ControlCaption(EPerlAppTextQueryInputField);
220 promptLabel->SetTextL(iPrompt);
223 /* TODO: OfferKeyEventL() so that newline can be seen as 'OK'.
224 * Or a hotkey for the button? */
226 #endif /* #ifdef __SERIES80__ */
228 static TInt TextQueryDialogL(const TDesC& aTitle, const TDesC& aPrompt, TDes& aData, const TInt aMaxLength)
231 CAknTextQueryDialog* dlg =
232 new (ELeave) CAknTextQueryDialog(aData);
233 dlg->SetPromptL(aPrompt);
234 dlg->SetMaxLength(aMaxLength);
235 return dlg->ExecuteLD(R_TEXT_QUERY_DIALOG);
236 #endif /* #ifdef __SERIES60__ */
239 CPerlAppTextQueryDialog* dlg =
240 new (ELeave) CPerlAppTextQueryDialog(data);
241 dlg->iTitle.Set(aTitle);
242 dlg->iPrompt.Set(aPrompt);
243 dlg->iMaxLength = aMaxLength;
244 if (dlg->ExecuteLD(R_PERL_ONELINER_DIALOG)) {
249 #endif /* #ifdef __SERIES80__ */
252 static TBool FileQueryDialogL(TDes& aFilename)
255 return AknCommonDialogs::RunSelectLD(aFilename,
256 R_MEMORY_SELECTION_DIALOG);
257 #endif /* #ifdef __SERIES60__ */
259 if (CCknOpenFileDialog::RunDlgLD(aFilename,
260 CCknFileListDialogBase::EShowAllDrives
261 |CCknFileListDialogBase::EShowSystemFilesAndFolders
262 |CCknFileListDialogBase::EShowBothFilesAndFolders
264 TEntry aEntry; // Be paranoid and check that the file is there.
267 if (aFs.Entry(aFilename, aEntry) == KErrNone)
270 CEikonEnv::Static()->InfoMsg(_L("File not found"));
273 #endif /* #ifdef __SERIES80__ */
276 // The isXXX() come from the Perl headers.
277 #define FILENAME_IS_ABSOLUTE(n) \
278 (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\')
280 static TBool IsInPerl(TFileName aFileName)
282 TInt offset = aFileName.FindF(KScriptPrefix);
283 return ((offset == 0 && // \foo
284 aFileName[0] == '\\')
286 (offset == 2 && // x:\foo
287 FILENAME_IS_ABSOLUTE(aFileName)));
290 static TBool IsInInbox(TFileName aFileName)
292 TInt offset = aFileName.FindF(KInboxPrefix);
293 return ((offset == 0 && // \foo
294 aFileName[0] == '\\')
296 (offset == 2 && // x:\foo
297 FILENAME_IS_ABSOLUTE(aFileName)));
300 static TBool IsPerlModule(TParsePtrC aParsed)
302 return aParsed.Ext().CompareF(_L(".pm")) == 0;
305 static TBool IsPerlScript(TParsePtrC aParsed)
307 return aParsed.Ext().CompareF(_L(".pl")) == 0;
310 static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst)
312 TBool proceed = ETrue;
313 TMessageBuffer message;
315 message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst);
316 if (OkCancelDialogL(message)) {
317 message.Format(_L("Install as %S?"), &aDst);
318 if (OkCancelDialogL(message)) {
319 if (BaflUtils::FileExists(aFs, aDst)) {
320 message.Format(_L("Replace old %S?"), &aDst);
321 if (!OkCancelDialogL(message))
326 TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst);
327 if (err == KErrNone) {
328 message.Format(_L("Installed %S"), &aDst);
329 InformationNoteL(message);
332 message.Format(_L("Failure %d installing %S"), err, &aDst);
333 WarningNoteL(message);
340 static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn)
343 TInt m = aFn.MaxLength();
344 TInt n = aPeekBuffer.Length();
349 // The following is a little regular expression
350 // engine that matches Perl package names.
351 if (j < n && isSPACE(aPeekBuffer[j])) {
352 while (j < n && isSPACE(aPeekBuffer[j])) j++;
353 if (j < n && isALPHA(aPeekBuffer[j])) {
354 while (j < n && isALNUM(aPeekBuffer[j])) {
356 isALNUM(aPeekBuffer[j]) &&
358 aFn[i++] = aPeekBuffer[j++];
360 aPeekBuffer[j ] == ':' &&
361 aPeekBuffer[j + 1] == ':' &&
366 isALPHA(aPeekBuffer[j])) {
368 isALNUM(aPeekBuffer[j]) &&
370 aFn[i++] = aPeekBuffer[j++];
374 while (j < n && isSPACE(aPeekBuffer[j])) j++;
375 if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) {
377 aFn.Append(_L(".pm"));
385 static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive)
387 TInt offset = aPeekBuffer.Find(_L8("package"));
388 if (offset != KErrNotFound) {
389 const TInt KPackageLen = 7;
392 if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q))
396 p.Copy(aDrive.Drive());
397 p.Append(KModulePrefix);
400 if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) {
403 for (j = 0; j < p.Length(); j++)
406 for (j = 0; j < q.Length(); j++)
415 static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer)
417 return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 &&
418 aPeekBuffer.Find(_L8("perl")) != KErrNotFound;
421 static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs)
424 TPtrC drive = aDrive.Drive();
425 TPtrC namext = aFile.NameAndExt();
427 aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext);
428 if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) {
430 if (IsPerlModule(aDst))
431 GuessPerlModule(aDst, aPeekBuffer, aDrive);
433 if (aDst.Length() > 0) {
434 CopyFromInboxL(aFs, aSrc, aDst);
441 static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer)
443 TBool isModule = EFalse;
445 if (IsInPerl(aScriptName) &&
446 (IsPerlScript(aScriptName) ||
447 (isModule = IsPerlModule(aScriptName)) ||
448 LooksLikePerlL(aPeekBuffer))) {
449 TMessageBuffer message;
452 message.Format(_L("Really run module %S?"), &aScriptName);
454 message.Format(_L("Run %S?"), &aScriptName);
455 if (YesNoDialogL(message))
456 DoRunScriptL(aScriptName);
463 void CPerlAppUi::InstallOrRunL(const TFileName& aFileName)
467 TMessageBuffer message;
469 aFile.Set(aFileName, NULL, NULL);
470 if (FILENAME_IS_ABSOLUTE(aFileName)) {
471 aDrive.Set(aFileName, NULL, NULL);
474 CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
475 aDrive.Set(appName, NULL, NULL);
478 iFs = &CEikonEnv::Static()->FsSession();
480 TInt err = f.Open(*iFs, aFileName, EFileRead);
481 if (err == KErrNone) {
482 TPeekBuffer aPeekBuffer;
483 err = f.Read(aPeekBuffer);
484 f.Close(); // Release quickly.
485 if (err == KErrNone) {
486 if (!(IsInInbox(aFileName) ?
487 InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) :
488 RunStuffL(aFileName, aPeekBuffer))) {
489 message.Format(_L("Failed for file %S"), &aFileName);
490 WarningNoteL(message);
493 message.Format(_L("Error %d reading %S"), err, &aFileName);
494 WarningNoteL(message);
497 message.Format(_L("Error %d opening %S"), err, &aFileName);
498 WarningNoteL(message);
501 delete CEikonEnv::Static()->EikAppUi();
506 #endif // #ifndef PerlAppMinimal
508 static void DoRunScriptL(TFileName aScriptName)
510 CPerlBase* perl = CPerlBase::NewInterpreterLC();
511 TRAPD(error, perl->RunScriptL(aScriptName));
512 #ifndef PerlAppMinimal
513 if (error != KErrNone) {
514 TMessageBuffer message;
515 message.Format(_L("Error %d"), error);
516 YesNoDialogL(message);
518 #endif // #ifndef PerlAppMinimal
519 CleanupStack::PopAndDestroy(perl);
522 #ifndef PerlAppMinimal
524 void CPerlAppUi::OpenFileL(const TDesC& aFileName)
526 InstallOrRunL(aFileName);
530 #endif // #ifndef PerlAppMinimal
532 TBool CPerlAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */)
534 if (aCommand == EApaCommandRun) {
535 TFileName appName = Application()->AppFullName();
537 p.Set(KDefaultScript, &appName, NULL);
541 if (aFs.Entry(p.FullName(), aEntry) == KErrNone) {
542 DoRunScriptL(p.FullName());
546 return aCommand == EApaCommandOpen ? ETrue : EFalse;
549 #ifndef PerlAppMinimal
551 void CPerlAppUi::SetFs(const RFs& aFs)
556 #endif // #ifndef PerlAppMinimal
558 static void DoHandleCommandL(TInt aCommand) {
559 #ifndef PerlAppMinimal
560 TMessageBuffer message;
561 #endif // #ifndef PerlAppMinimal
565 #ifndef PerlAppMinimal
566 case EPerlAppCommandAbout:
568 message.Format(KAboutFormat,
572 PERL_SYMBIANPORT_MAJOR,
573 PERL_SYMBIANPORT_MINOR,
574 PERL_SYMBIANPORT_PATCH,
576 PERL_SYMBIANSDK_MAJOR,
577 PERL_SYMBIANSDK_MINOR
579 InformationNoteL(message);
582 case EPerlAppCommandTime:
584 CPerlBase* perl = CPerlBase::NewInterpreterLC();
585 const char *const argv[] =
587 "print 'Running in ', $^O, \"\\n\", scalar localtime" };
588 perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0);
589 CleanupStack::PopAndDestroy(perl);
592 case EPerlAppCommandRunFile:
594 TFileName aScriptUtf16;
595 aScriptUtf16.Copy(_L("C:\\"));
596 if (FileQueryDialogL(aScriptUtf16))
597 DoRunScriptL(aScriptUtf16);
600 case EPerlAppCommandOneLiner:
603 _LIT(prompt, "Oneliner:");
604 #endif /* #ifdef __SERIES60__ */
606 _LIT(prompt, "Code:"); // The title has "Oneliner" already.
607 #endif /* #ifdef __SERIES80__ */
609 STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
610 if (TextQueryDialogL(_L("Oneliner"),
613 KPerlAppOneLinerSize)) {
614 const TUint KPerlAppUtf8Multi = 3;
615 TBuf8<KPerlAppUtf8Multi * KPerlAppOneLinerSize> utf8;
617 CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8, cAppUi->iOneLiner);
618 CPerlBase* perl = CPerlBase::NewInterpreterLC();
620 char **argv = (char**) malloc(argc * sizeof(char *));
621 User::LeaveIfNull(argv);
623 TCleanupItem argvCleanupItem = TCleanupItem(free, argv);
624 CleanupStack::PushL(argvCleanupItem);
625 argv[0] = (char *) "perl";
626 argv[1] = (char *) "-le";
627 argv[2] = (char *) utf8.PtrZ();
628 perl->ParseAndRun(argc, argv);
629 CleanupStack::PopAndDestroy(2, perl);
633 case EPerlAppCommandCopyright:
635 message.Format(KCopyrightFormat);
636 InformationNoteL(message);
639 case EPerlAppCommandAboutCopyright:
643 m1.Format(KAboutFormat,
647 PERL_SYMBIANPORT_MAJOR,
648 PERL_SYMBIANPORT_MINOR,
649 PERL_SYMBIANPORT_PATCH,
651 PERL_SYMBIANSDK_MAJOR,
652 PERL_SYMBIANSDK_MINOR
654 InformationNoteL(m1);
655 User::After((TTimeIntervalMicroSeconds32) (1000*1000));
656 m2.Format(KCopyrightFormat);
657 InformationNoteL(m2);
660 #endif // #ifndef PerlAppMinimal
662 Panic(EPerlAppCommandUnknown);
668 void CPerlAppUi::HandleCommandL(TInt aCommand)
673 case EAknSoftkeyExit:
677 DoHandleCommandL(aCommand);
682 #endif /* #ifdef __SERIES60__ */
686 void CPerlAppView::HandleCommandL(TInt aCommand) {
687 DoHandleCommandL(aCommand);
690 void CPerlAppUi::HandleCommandL(TInt aCommand) {
697 iAppView->HandleCommandL(aCommand);
702 #endif /* #ifdef __SERIES80__ */
704 CPerlAppView* CPerlAppView::NewL(const TRect& aRect)
706 CPerlAppView* self = CPerlAppView::NewLC(aRect);
707 CleanupStack::Pop(self);
711 CPerlAppView* CPerlAppView::NewLC(const TRect& aRect)
713 CPerlAppView* self = new (ELeave) CPerlAppView;
714 CleanupStack::PushL(self);
715 self->ConstructL(aRect);
719 void CPerlAppView::ConstructL(const TRect& aRect)
726 CPerlAppView::~CPerlAppView()
730 void CPerlAppView::Draw(const TRect& /*aRect*/) const
732 CWindowGc& gc = SystemGc();
737 CApaDocument* CPerlAppApplication::CreateDocumentL()
739 CPerlAppDocument* document = new (ELeave) CPerlAppDocument(*this);
743 CEikAppUi* CPerlAppDocument::CreateAppUiL()
745 CPerlAppUi* appui = new (ELeave) CPerlAppUi();
750 #ifndef PerlAppMinimal
752 CFileStore* CPerlAppDocument::OpenFileL(TBool aDoOpen, const TDesC& aFileName, RFs& aFs)
755 STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
758 appui->OpenFileL(aFileName);
762 #endif // #ifndef PerlAppMinimal
764 EXPORT_C CApaApplication* NewApplication()
766 return new CPerlAppApplication;
769 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)