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"
29 #include "patchlevel.h"
32 const TUid KPerlAppUid = { 0x102015F6 };
34 // This is like the Symbian _LIT() but without the embedded L prefix,
35 // which enables using #defined constants (which need to carry their
38 #define _LIT_NO_L(n, s) static const TLitC<sizeof(s)/2> n={sizeof(s)/2-1,s}
39 #endif // #ifndef _LIT_NO_L
41 _LIT(KAppName, "PerlApp");
42 _LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR);
44 "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d");
45 _LIT(KCopyrightFormat,
46 "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005");
47 _LIT(KInboxPrefix, "\\System\\Mail\\");
48 _LIT(KScriptPrefix, "\\Perl\\");
50 _LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h
52 typedef TBuf<256> TMessageBuffer;
53 typedef TBuf8<256> TPeekBuffer;
54 typedef TBuf8<256> TFileName8;
56 // Usage: DEBUG_PRINTF((_L("%S"), &aStr))
58 #define DEBUG_PRINTF(s) {TMessageBuffer message; message.Format s; YesNoDialogL(message);}
61 TUid CPerlAppApplication::AppDllUid() const
68 EPerlAppCommandUnknown = 1
71 void Panic(TPerlAppPanic aReason)
73 User::Panic(KAppName, aReason);
76 void CPerlAppUi::ConstructL()
79 iAppView = CPerlAppView::NewL(ClientRect());
80 AddToStackL(iAppView);
82 CEikonEnv::Static()->DisableExitChecks(ETrue); // Symbian FAQ-0577.
85 CPerlAppUi::~CPerlAppUi()
88 iEikonEnv->RemoveFromStack(iAppView);
96 if (iDoorObserver) // Otherwise the embedding application waits forever.
97 iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty);
100 static TBool DlgOk(CAknNoteDialog* dlg)
102 return dlg && dlg->RunDlgLD() == EAknSoftkeyOk;
105 static TBool OkCancelDialogL(TDesC& aMessage)
107 CAknNoteDialog* dlg =
108 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
109 dlg->PrepareLC(R_OK_CANCEL_DIALOG);
110 dlg->SetTextL(aMessage);
114 static TBool YesNoDialogL(TDesC& aMessage)
116 CAknNoteDialog* dlg =
117 new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
118 dlg->PrepareLC(R_YES_NO_DIALOG);
119 dlg->SetTextL(aMessage);
123 static TInt InformationNoteL(TDesC& aMessage)
125 CAknInformationNote* note = new (ELeave) CAknInformationNote;
126 return note->ExecuteLD(aMessage);
129 static TInt ConfirmationNoteL(TDesC& aMessage)
131 CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote;
132 return note->ExecuteLD(aMessage);
135 static TInt WarningNoteL(TDesC& aMessage)
137 CAknWarningNote* note = new (ELeave) CAknWarningNote;
138 return note->ExecuteLD(aMessage);
141 static TInt TextQueryDialogL(const TDesC& aPrompt, TDes& aData, const TInt aMaxLength)
143 CAknTextQueryDialog* dlg =
144 new (ELeave) CAknTextQueryDialog(aData);
145 dlg->SetPromptL(aPrompt);
146 dlg->SetMaxLength(aMaxLength);
147 return dlg->ExecuteLD(R_TEXT_QUERY_DIALOG);
150 // The isXXX() come from the Perl headers.
151 #define FILENAME_IS_ABSOLUTE(n) \
152 (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\')
154 static TBool IsInPerl(TFileName aFileName)
156 TInt offset = aFileName.FindF(KScriptPrefix);
157 return ((offset == 0 && // \foo
158 aFileName[0] == '\\')
160 (offset == 2 && // x:\foo
161 FILENAME_IS_ABSOLUTE(aFileName)));
164 static TBool IsInInbox(TFileName aFileName)
166 TInt offset = aFileName.FindF(KInboxPrefix);
167 return ((offset == 0 && // \foo
168 aFileName[0] == '\\')
170 (offset == 2 && // x:\foo
171 FILENAME_IS_ABSOLUTE(aFileName)));
174 static TBool IsPerlModule(TParsePtrC aParsed)
176 return aParsed.Ext().CompareF(_L(".pm")) == 0;
179 static TBool IsPerlScript(TParsePtrC aParsed)
181 return aParsed.Ext().CompareF(_L(".pl")) == 0;
184 static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst)
186 TBool proceed = ETrue;
187 TMessageBuffer message;
189 message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst);
190 if (OkCancelDialogL(message)) {
191 message.Format(_L("Install as %S?"), &aDst);
192 if (OkCancelDialogL(message)) {
193 if (BaflUtils::FileExists(aFs, aDst)) {
194 message.Format(_L("Replace old %S?"), &aDst);
195 if (!OkCancelDialogL(message))
200 TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst);
201 if (err == KErrNone) {
202 message.Format(_L("Installed %S"), &aDst);
203 ConfirmationNoteL(message);
206 message.Format(_L("Failure %d installing %S"), err, &aDst);
207 WarningNoteL(message);
214 static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn)
217 TInt m = aFn.MaxLength();
218 TInt n = aPeekBuffer.Length();
223 // The following is a little regular expression
224 // engine that matches Perl package names.
225 if (j < n && isSPACE(aPeekBuffer[j])) {
226 while (j < n && isSPACE(aPeekBuffer[j])) j++;
227 if (j < n && isALPHA(aPeekBuffer[j])) {
228 while (j < n && isALNUM(aPeekBuffer[j])) {
230 isALNUM(aPeekBuffer[j]) &&
232 aFn[i++] = aPeekBuffer[j++];
234 aPeekBuffer[j ] == ':' &&
235 aPeekBuffer[j + 1] == ':' &&
240 isALPHA(aPeekBuffer[j])) {
242 isALNUM(aPeekBuffer[j]) &&
244 aFn[i++] = aPeekBuffer[j++];
248 while (j < n && isSPACE(aPeekBuffer[j])) j++;
249 if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) {
251 aFn.Append(_L(".pm"));
259 static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive)
261 TInt offset = aPeekBuffer.Find(_L8("package"));
262 if (offset != KErrNotFound) {
263 const TInt KPackageLen = 7;
266 if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q))
270 p.Copy(aDrive.Drive());
271 p.Append(KModulePrefix);
274 if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) {
277 for (j = 0; j < p.Length(); j++)
280 for (j = 0; j < q.Length(); j++)
289 static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer)
291 return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 &&
292 aPeekBuffer.Find(_L8("perl")) != KErrNotFound;
295 static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs)
298 TPtrC drive = aDrive.Drive();
299 TPtrC namext = aFile.NameAndExt();
301 aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext);
302 if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) {
304 if (IsPerlModule(aDst))
305 GuessPerlModule(aDst, aPeekBuffer, aDrive);
307 if (aDst.Length() > 0) {
308 CopyFromInboxL(aFs, aSrc, aDst);
315 static void DoRunScriptL(TFileName aScriptName)
317 CPerlBase* perl = CPerlBase::NewInterpreterLC();
318 TRAPD(error, perl->RunScriptL(aScriptName));
319 if (error != KErrNone) {
320 TMessageBuffer message;
321 message.Format(_L("Error %d"), error);
322 YesNoDialogL(message);
324 CleanupStack::PopAndDestroy(perl);
327 static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer)
329 TBool isModule = EFalse;
331 if (IsInPerl(aScriptName) &&
332 (IsPerlScript(aScriptName) ||
333 (isModule = IsPerlModule(aScriptName)) ||
334 LooksLikePerlL(aPeekBuffer))) {
335 TMessageBuffer message;
338 message.Format(_L("Really run module %S?"), &aScriptName);
340 message.Format(_L("Run %S?"), &aScriptName);
341 if (YesNoDialogL(message))
342 DoRunScriptL(aScriptName);
350 void CPerlAppUi::InstallOrRunL(const TFileName& aFileName)
354 TMessageBuffer message;
356 aFile.Set(aFileName, NULL, NULL);
357 if (FILENAME_IS_ABSOLUTE(aFileName)) {
358 aDrive.Set(aFileName, NULL, NULL);
361 CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
362 aDrive.Set(appName, NULL, NULL);
365 iFs = &CEikonEnv::Static()->FsSession();
367 TInt err = f.Open(*iFs, aFileName, EFileRead);
368 if (err == KErrNone) {
369 TPeekBuffer aPeekBuffer;
370 err = f.Read(aPeekBuffer);
371 f.Close(); // Release quickly.
372 if (err == KErrNone) {
373 if (!(IsInInbox(aFileName) ?
374 InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) :
375 RunStuffL(aFileName, aPeekBuffer))) {
376 message.Format(_L("Failed for file %S"), &aFileName);
377 WarningNoteL(message);
380 message.Format(_L("Error %d reading %S"), err, &aFileName);
381 WarningNoteL(message);
384 message.Format(_L("Error %d opening %S"), err, &aFileName);
385 WarningNoteL(message);
388 delete CEikonEnv::Static()->EikAppUi();
393 void CPerlAppUi::OpenFileL(const TDesC& aFileName)
395 InstallOrRunL(aFileName);
399 TBool CPerlAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */)
401 return aCommand == EApaCommandOpen ? ETrue : EFalse;
404 void CPerlAppUi::SetFs(const RFs& aFs)
409 void CPerlAppUi::HandleCommandL(TInt aCommand)
411 TMessageBuffer message;
416 case EAknSoftkeyExit:
419 case EPerlAppCommandAbout:
421 message.Format(KAboutFormat,
425 PERL_SYMBIANPORT_MAJOR,
426 PERL_SYMBIANPORT_MINOR,
427 PERL_SYMBIANPORT_PATCH,
429 PERL_SYMBIANSDK_MAJOR,
430 PERL_SYMBIANSDK_MINOR
432 InformationNoteL(message);
435 case EPerlAppCommandTime:
437 CPerlBase* perl = CPerlBase::NewInterpreterLC();
438 const char *const argv[] =
440 "print 'Running in ', $^O, \"\\n\", scalar localtime" };
441 perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0);
442 CleanupStack::PopAndDestroy(perl);
445 case EPerlAppCommandRunFile:
447 InformationNoteL(message);
448 TFileName aScriptUtf16;
449 if (AknCommonDialogs::RunSelectDlgLD(aScriptUtf16,
450 R_MEMORY_SELECTION_DIALOG))
451 DoRunScriptL(aScriptUtf16);
454 case EPerlAppCommandOneLiner:
456 _LIT(prompt, "Oneliner:");
457 if (TextQueryDialogL(prompt, iOneLiner, KPerlAppOneLinerSize)) {
458 const TUint KPerlAppUtf8Multi = 3;
459 TBuf8<KPerlAppUtf8Multi * KPerlAppOneLinerSize> utf8;
461 CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8, iOneLiner);
462 CPerlBase* perl = CPerlBase::NewInterpreterLC();
464 char **argv = (char**) malloc(argc * sizeof(char *));
465 User::LeaveIfNull(argv);
467 TCleanupItem argvCleanupItem = TCleanupItem(free, argv);
468 CleanupStack::PushL(argvCleanupItem);
469 argv[0] = (char *) "perl";
470 argv[1] = (char *) "-le";
471 argv[2] = (char *) utf8.PtrZ();
472 perl->ParseAndRun(argc, argv);
473 CleanupStack::PopAndDestroy(2, perl);
477 case EPerlAppCommandCopyright:
479 message.Format(KCopyrightFormat);
480 InformationNoteL(message);
485 Panic(EPerlAppCommandUnknown);
490 CPerlAppView* CPerlAppView::NewL(const TRect& aRect)
492 CPerlAppView* self = CPerlAppView::NewLC(aRect);
493 CleanupStack::Pop(self);
497 CPerlAppView* CPerlAppView::NewLC(const TRect& aRect)
499 CPerlAppView* self = new (ELeave) CPerlAppView;
500 CleanupStack::PushL(self);
501 self->ConstructL(aRect);
505 void CPerlAppView::ConstructL(const TRect& aRect)
512 void CPerlAppView::Draw(const TRect& /*aRect*/) const
514 CWindowGc& gc = SystemGc();
519 CApaDocument* CPerlAppApplication::CreateDocumentL()
521 CPerlAppDocument* document = new (ELeave) CPerlAppDocument(*this);
525 CEikAppUi* CPerlAppDocument::CreateAppUiL()
527 CPerlAppUi* appui = new (ELeave) CPerlAppUi();
531 CFileStore* CPerlAppDocument::OpenFileL(TBool /* aDoOpen */, const TDesC& aFileName, RFs& aFs)
534 STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
536 appui->OpenFileL(aFileName);
540 EXPORT_C CApaApplication* NewApplication()
542 return new CPerlAppApplication;
545 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)