1 /* Copyright (c) 2004-2005 Nokia. All rights reserved. */
3 /* The PerlApp application is licensed under the same terms as Perl itself. */
8 #include <aknnotewrappers.h>
18 #include <AknCommonDialogs.h>
20 #ifndef __SERIES60_1X__
21 #include <CAknFileSelectionDialog.h>
26 #include "PerlApp.hrh"
27 #include "PerlApp.rsg"
33 const TUid KPerlAppUid = { 0x102015F6 };
35 // This is like the Symbian _LIT() but without the embedded L prefix,
36 // which enables using #defined constants (which need to carry their
39 #define _LIT_NO_L(n, s) static const TLitC<sizeof(s)/2> n={sizeof(s)/2-1,s}
40 #endif // #ifndef _LIT_NO_L
42 _LIT(KAppName, "PerlApp");
43 _LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR);
45 "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d");
46 _LIT(KCopyrightFormat,
47 "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005");
48 _LIT(KInboxPrefix, "\\System\\Mail\\");
49 _LIT(KScriptPrefix, "\\Perl\\");
51 _LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h
53 typedef TBuf<256> TMessageBuffer;
54 typedef TBuf8<256> TPeekBuffer;
55 typedef TBuf8<256> TFileName8;
57 // Usage: DEBUG_PRINTF((_L("%S"), &aStr))
59 #define DEBUG_PRINTF(s) {TMessageBuffer message; message.Format s; YesNoDialogL(message);}
62 TUid CPerlAppApplication::AppDllUid() const
69 EPerlAppCommandUnknown = 1
72 void Panic(TPerlAppPanic aReason)
74 User::Panic(KAppName, aReason);
77 void CPerlAppUi::ConstructL()
80 iAppView = CPerlAppView::NewL(ClientRect());
81 AddToStackL(iAppView);
83 CEikonEnv::Static()->DisableExitChecks(ETrue); // Symbian FAQ-0577.
86 CPerlAppUi::~CPerlAppUi()
89 iEikonEnv->RemoveFromStack(iAppView);
97 if (iDoorObserver) // Otherwise the embedding application waits forever.
98 iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty);
101 static TBool DlgOk(CAknNoteDialog* dlg)
103 return dlg && dlg->RunDlgLD() == EAknSoftkeyOk;
106 static TBool OkCancelDialogL(TDesC& aMessage)
108 CAknNoteDialog* dlg =
109 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
110 dlg->PrepareLC(R_OK_CANCEL_DIALOG);
111 dlg->SetTextL(aMessage);
115 static TBool YesNoDialogL(TDesC& aMessage)
117 CAknNoteDialog* dlg =
118 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
119 dlg->PrepareLC(R_YES_NO_DIALOG);
120 dlg->SetTextL(aMessage);
124 static TInt InformationNoteL(TDesC& aMessage)
126 CAknInformationNote* note = new (ELeave) CAknInformationNote;
127 return note->ExecuteLD(aMessage);
130 static TInt ConfirmationNoteL(TDesC& aMessage)
132 CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote;
133 return note->ExecuteLD(aMessage);
136 static TInt WarningNoteL(TDesC& aMessage)
138 CAknWarningNote* note = new (ELeave) CAknWarningNote;
139 return note->ExecuteLD(aMessage);
142 static TInt TextQueryDialogL(const TDesC& aPrompt, TDes& aData, const TInt aMaxLength)
144 CAknTextQueryDialog* dlg =
145 new (ELeave) CAknTextQueryDialog(aData);
146 dlg->SetPromptL(aPrompt);
147 dlg->SetMaxLength(aMaxLength);
148 return dlg->ExecuteLD(R_TEXT_QUERY_DIALOG);
151 // The isXXX() come from the Perl headers.
152 #define FILENAME_IS_ABSOLUTE(n) \
153 (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\')
155 static TBool IsInPerl(TFileName aFileName)
157 TInt offset = aFileName.FindF(KScriptPrefix);
158 return ((offset == 0 && // \foo
159 aFileName[0] == '\\')
161 (offset == 2 && // x:\foo
162 FILENAME_IS_ABSOLUTE(aFileName)));
165 static TBool IsInInbox(TFileName aFileName)
167 TInt offset = aFileName.FindF(KInboxPrefix);
168 return ((offset == 0 && // \foo
169 aFileName[0] == '\\')
171 (offset == 2 && // x:\foo
172 FILENAME_IS_ABSOLUTE(aFileName)));
175 static TBool IsPerlModule(TParsePtrC aParsed)
177 return aParsed.Ext().CompareF(_L(".pm")) == 0;
180 static TBool IsPerlScript(TParsePtrC aParsed)
182 return aParsed.Ext().CompareF(_L(".pl")) == 0;
185 static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst)
187 TBool proceed = ETrue;
188 TMessageBuffer message;
190 message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst);
191 if (OkCancelDialogL(message)) {
192 message.Format(_L("Install as %S?"), &aDst);
193 if (OkCancelDialogL(message)) {
194 if (BaflUtils::FileExists(aFs, aDst)) {
195 message.Format(_L("Replace old %S?"), &aDst);
196 if (!OkCancelDialogL(message))
201 TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst);
202 if (err == KErrNone) {
203 message.Format(_L("Installed %S"), &aDst);
204 ConfirmationNoteL(message);
207 message.Format(_L("Failure %d installing %S"), err, &aDst);
208 WarningNoteL(message);
215 static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn)
218 TInt m = aFn.MaxLength();
219 TInt n = aPeekBuffer.Length();
224 // The following is a little regular expression
225 // engine that matches Perl package names.
226 if (j < n && isSPACE(aPeekBuffer[j])) {
227 while (j < n && isSPACE(aPeekBuffer[j])) j++;
228 if (j < n && isALPHA(aPeekBuffer[j])) {
229 while (j < n && isALNUM(aPeekBuffer[j])) {
231 isALNUM(aPeekBuffer[j]) &&
233 aFn[i++] = aPeekBuffer[j++];
235 aPeekBuffer[j ] == ':' &&
236 aPeekBuffer[j + 1] == ':' &&
241 isALPHA(aPeekBuffer[j])) {
243 isALNUM(aPeekBuffer[j]) &&
245 aFn[i++] = aPeekBuffer[j++];
249 while (j < n && isSPACE(aPeekBuffer[j])) j++;
250 if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) {
252 aFn.Append(_L(".pm"));
260 static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive)
262 TInt offset = aPeekBuffer.Find(_L8("package"));
263 if (offset != KErrNotFound) {
264 const TInt KPackageLen = 7;
267 if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q))
271 p.Copy(aDrive.Drive());
272 p.Append(KModulePrefix);
275 if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) {
278 for (j = 0; j < p.Length(); j++)
281 for (j = 0; j < q.Length(); j++)
290 static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer)
292 return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 &&
293 aPeekBuffer.Find(_L8("perl")) != KErrNotFound;
296 static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs)
299 TPtrC drive = aDrive.Drive();
300 TPtrC namext = aFile.NameAndExt();
302 aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext);
303 if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) {
305 if (IsPerlModule(aDst))
306 GuessPerlModule(aDst, aPeekBuffer, aDrive);
308 if (aDst.Length() > 0) {
309 CopyFromInboxL(aFs, aSrc, aDst);
316 static void DoRunScriptL(TFileName aScriptName)
318 CPerlBase* perl = CPerlBase::NewInterpreterLC();
319 TRAPD(error, perl->RunScriptL(aScriptName));
320 if (error != KErrNone) {
321 TMessageBuffer message;
322 message.Format(_L("Error %d"), error);
323 YesNoDialogL(message);
325 CleanupStack::PopAndDestroy(perl);
328 static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer)
330 TBool isModule = EFalse;
332 if (IsInPerl(aScriptName) &&
333 (IsPerlScript(aScriptName) ||
334 (isModule = IsPerlModule(aScriptName)) ||
335 LooksLikePerlL(aPeekBuffer))) {
336 TMessageBuffer message;
339 message.Format(_L("Really run module %S?"), &aScriptName);
341 message.Format(_L("Run %S?"), &aScriptName);
342 if (YesNoDialogL(message))
343 DoRunScriptL(aScriptName);
351 void CPerlAppUi::InstallOrRunL(const TFileName& aFileName)
355 TMessageBuffer message;
357 aFile.Set(aFileName, NULL, NULL);
358 if (FILENAME_IS_ABSOLUTE(aFileName)) {
359 aDrive.Set(aFileName, NULL, NULL);
362 CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
363 aDrive.Set(appName, NULL, NULL);
366 iFs = &CEikonEnv::Static()->FsSession();
368 TInt err = f.Open(*iFs, aFileName, EFileRead);
369 if (err == KErrNone) {
370 TPeekBuffer aPeekBuffer;
371 err = f.Read(aPeekBuffer);
372 f.Close(); // Release quickly.
373 if (err == KErrNone) {
374 if (!(IsInInbox(aFileName) ?
375 InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) :
376 RunStuffL(aFileName, aPeekBuffer))) {
377 message.Format(_L("Failed for file %S"), &aFileName);
378 WarningNoteL(message);
381 message.Format(_L("Error %d reading %S"), err, &aFileName);
382 WarningNoteL(message);
385 message.Format(_L("Error %d opening %S"), err, &aFileName);
386 WarningNoteL(message);
389 delete CEikonEnv::Static()->EikAppUi();
394 void CPerlAppUi::OpenFileL(const TDesC& aFileName)
396 InstallOrRunL(aFileName);
400 TBool CPerlAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */)
402 return aCommand == EApaCommandOpen ? ETrue : EFalse;
405 void CPerlAppUi::SetFs(const RFs& aFs)
410 void CPerlAppUi::HandleCommandL(TInt aCommand)
412 TMessageBuffer message;
417 case EAknSoftkeyExit:
420 case EPerlAppCommandAbout:
422 message.Format(KAboutFormat,
426 PERL_SYMBIANPORT_MAJOR,
427 PERL_SYMBIANPORT_MINOR,
428 PERL_SYMBIANPORT_PATCH,
430 PERL_SYMBIANSDK_MAJOR,
431 PERL_SYMBIANSDK_MINOR
433 InformationNoteL(message);
436 case EPerlAppCommandTime:
438 CPerlBase* perl = CPerlBase::NewInterpreterLC();
439 const char *const argv[] =
441 "print 'Running in ', $^O, \"\\n\", scalar localtime" };
442 perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0);
443 CleanupStack::PopAndDestroy(perl);
446 case EPerlAppCommandRunFile:
448 InformationNoteL(message);
449 TFileName aScriptUtf16;
450 if (AknCommonDialogs::RunSelectDlgLD(aScriptUtf16,
451 R_MEMORY_SELECTION_DIALOG))
452 DoRunScriptL(aScriptUtf16);
455 case EPerlAppCommandOneLiner:
457 _LIT(prompt, "Oneliner:");
458 if (TextQueryDialogL(prompt, iOneLiner, KPerlAppOneLinerSize)) {
459 const TUint KPerlAppUtf8Multi = 3;
460 TBuf8<KPerlAppUtf8Multi * KPerlAppOneLinerSize> utf8;
462 CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8, iOneLiner);
463 CPerlBase* perl = CPerlBase::NewInterpreterLC();
465 char **argv = (char**) malloc(argc * sizeof(char *));
466 User::LeaveIfNull(argv);
468 TCleanupItem argvCleanupItem = TCleanupItem(free, argv);
469 CleanupStack::PushL(argvCleanupItem);
470 argv[0] = (char *) "perl";
471 argv[1] = (char *) "-le";
472 argv[2] = (char *) utf8.PtrZ();
473 perl->ParseAndRun(argc, argv);
474 CleanupStack::PopAndDestroy(2, perl);
478 case EPerlAppCommandCopyright:
480 message.Format(KCopyrightFormat);
481 InformationNoteL(message);
486 Panic(EPerlAppCommandUnknown);
491 CPerlAppView* CPerlAppView::NewL(const TRect& aRect)
493 CPerlAppView* self = CPerlAppView::NewLC(aRect);
494 CleanupStack::Pop(self);
498 CPerlAppView* CPerlAppView::NewLC(const TRect& aRect)
500 CPerlAppView* self = new (ELeave) CPerlAppView;
501 CleanupStack::PushL(self);
502 self->ConstructL(aRect);
506 void CPerlAppView::ConstructL(const TRect& aRect)
513 void CPerlAppView::Draw(const TRect& /*aRect*/) const
515 CWindowGc& gc = SystemGc();
520 CApaDocument* CPerlAppApplication::CreateDocumentL()
522 CPerlAppDocument* document = new (ELeave) CPerlAppDocument(*this);
526 CEikAppUi* CPerlAppDocument::CreateAppUiL()
528 CPerlAppUi* appui = new (ELeave) CPerlAppUi();
532 CFileStore* CPerlAppDocument::OpenFileL(TBool /* aDoOpen */, const TDesC& aFileName, RFs& aFs)
535 STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
537 appui->OpenFileL(aFileName);
541 EXPORT_C CApaApplication* NewApplication()
543 return new CPerlAppApplication;
546 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)