diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2005-04-18 16:18:30 +0300 |
---|---|---|
committer | Rafael Garcia-Suarez <rgarciasuarez@gmail.com> | 2005-04-21 15:38:30 +0000 |
commit | 27da23d53ccce622bc51822f59df8def79b4df95 (patch) | |
tree | 1202440e0fbf7a2fc1bb54993d11cda7b245f1b4 /symbian | |
parent | ec0624293b57ae07d6b2c32bae099d4f163e7e07 (diff) | |
download | perl-27da23d53ccce622bc51822f59df8def79b4df95.tar.gz |
Symbian port of Perl
Message-ID: <B356D8F434D20B40A8CEDAEC305A1F2453D653@esebe105.NOE.Nokia.com>
p4raw-id: //depot/perl@24271
Diffstat (limited to 'symbian')
-rw-r--r-- | symbian/PerlApp.cpp | 549 | ||||
-rw-r--r-- | symbian/PerlApp.h | 60 | ||||
-rw-r--r-- | symbian/PerlApp.hrh | 17 | ||||
-rw-r--r-- | symbian/PerlApp.rss | 141 | ||||
-rw-r--r-- | symbian/PerlAppAif.rss | 21 | ||||
-rw-r--r-- | symbian/PerlBase.cpp | 409 | ||||
-rw-r--r-- | symbian/PerlBase.h | 118 | ||||
-rw-r--r-- | symbian/PerlBase.pod | 202 | ||||
-rw-r--r-- | symbian/PerlRecog.cpp | 57 | ||||
-rw-r--r-- | symbian/PerlRecog.mmp | 9 | ||||
-rw-r--r-- | symbian/README | 20 | ||||
-rw-r--r-- | symbian/TODO | 150 | ||||
-rw-r--r-- | symbian/bld.inf | 4 | ||||
-rw-r--r-- | symbian/config.pl | 768 | ||||
-rw-r--r-- | symbian/config.sh | 768 | ||||
-rw-r--r-- | symbian/cwd.pl | 6 | ||||
-rw-r--r-- | symbian/demo_pl | 128 | ||||
-rw-r--r-- | symbian/install.cfg | 108 | ||||
-rw-r--r-- | symbian/makesis.pl | 185 | ||||
-rw-r--r-- | symbian/port.pl | 6 | ||||
-rw-r--r-- | symbian/sanity.pl | 28 | ||||
-rw-r--r-- | symbian/sdk.pl | 48 | ||||
-rw-r--r-- | symbian/symbian_dll.cpp | 20 | ||||
-rw-r--r-- | symbian/symbian_proto.h | 72 | ||||
-rw-r--r-- | symbian/symbian_stubs.c | 112 | ||||
-rw-r--r-- | symbian/symbian_stubs.h | 22 | ||||
-rw-r--r-- | symbian/symbian_utils.cpp | 299 | ||||
-rw-r--r-- | symbian/symbianish.h | 209 | ||||
-rw-r--r-- | symbian/uid.pl | 1 | ||||
-rw-r--r-- | symbian/version.pl | 22 | ||||
-rw-r--r-- | symbian/xsbuild.pl | 861 |
31 files changed, 5420 insertions, 0 deletions
diff --git a/symbian/PerlApp.cpp b/symbian/PerlApp.cpp new file mode 100644 index 0000000000..319a59118c --- /dev/null +++ b/symbian/PerlApp.cpp @@ -0,0 +1,549 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The PerlApp application is licensed under the same terms as Perl itself. */ + +#include "PerlApp.h" + +#include <avkon.hrh> +#include <aknnotewrappers.h> +#include <apparc.h> +#include <e32base.h> +#include <e32cons.h> +#include <eikenv.h> +#include <bautils.h> +#include <eikappui.h> +#include <utf.h> +#include <f32file.h> + +#include <AknCommonDialogs.h> + +#ifndef __SERIES60_1X__ +#include <CAknFileSelectionDialog.h> +#endif + +#include <coemain.h> + +#include "PerlApp.hrh" +#include "PerlApp.rsg" + +#include "patchlevel.h" +#include "PerlBase.h" + +const TUid KPerlAppUid = { 0x102015F6 }; + +// This is like the Symbian _LIT() but without the embedded L prefix, +// which enables using #defined constants (which need to carry their +// own L prefix). +#ifndef _LIT_NO_L +#define _LIT_NO_L(n, s) static const TLitC<sizeof(s)/2> n={sizeof(s)/2-1,s} +#endif // #ifndef _LIT_NO_L + +_LIT(KAppName, "PerlApp"); +_LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR); +_LIT(KAboutFormat, + "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d"); +_LIT(KCopyrightFormat, + "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005"); +_LIT(KInboxPrefix, "\\System\\Mail\\"); +_LIT(KScriptPrefix, "\\Perl\\"); + +_LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h + +typedef TBuf<256> TMessageBuffer; +typedef TBuf8<256> TPeekBuffer; +typedef TBuf8<256> TFileName8; + +// Usage: DEBUG_PRINTF((_L("%S"), &aStr)) +#if 1 +#define DEBUG_PRINTF(s) {TMessageBuffer message; message.Format s; YesNoDialogL(message);} +#endif + +TUid CPerlAppApplication::AppDllUid() const +{ + return KPerlAppUid; +} + +enum TPerlAppPanic +{ + EPerlAppCommandUnknown = 1 +}; + +void Panic(TPerlAppPanic aReason) +{ + User::Panic(KAppName, aReason); +} + +void CPerlAppUi::ConstructL() +{ + BaseConstructL(); + iAppView = CPerlAppView::NewL(ClientRect()); + AddToStackL(iAppView); + iFs = NULL; + CEikonEnv::Static()->DisableExitChecks(ETrue); // Symbian FAQ-0577. +} + +CPerlAppUi::~CPerlAppUi() +{ + if (iAppView) { + iEikonEnv->RemoveFromStack(iAppView); + delete iAppView; + iAppView = NULL; + } + if (iFs) { + delete iFs; + iFs = NULL; + } + if (iDoorObserver) // Otherwise the embedding application waits forever. + iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty); +} + +static TBool DlgOk(CAknNoteDialog* dlg) +{ + return dlg && dlg->RunDlgLD() == EAknSoftkeyOk; +} + +static TBool OkCancelDialogL(TDesC& aMessage) +{ + CAknNoteDialog* dlg = + new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone); + dlg->PrepareLC(R_OK_CANCEL_DIALOG); + dlg->SetTextL(aMessage); + return DlgOk(dlg); +} + +static TBool YesNoDialogL(TDesC& aMessage) +{ + CAknNoteDialog* dlg = + new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone); + dlg->PrepareLC(R_YES_NO_DIALOG); + dlg->SetTextL(aMessage); + return DlgOk(dlg); +} + +static TInt InformationNoteL(TDesC& aMessage) +{ + CAknInformationNote* note = new (ELeave) CAknInformationNote; + return note->ExecuteLD(aMessage); +} + +static TInt ConfirmationNoteL(TDesC& aMessage) +{ + CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote; + return note->ExecuteLD(aMessage); +} + +static TInt WarningNoteL(TDesC& aMessage) +{ + CAknWarningNote* note = new (ELeave) CAknWarningNote; + return note->ExecuteLD(aMessage); +} + +static TInt TextQueryDialogL(const TDesC& aPrompt, TDes& aData, const TInt aMaxLength) +{ + CAknTextQueryDialog* dlg = + new (ELeave) CAknTextQueryDialog(aData); + dlg->SetPromptL(aPrompt); + dlg->SetMaxLength(aMaxLength); + return dlg->ExecuteLD(R_TEXT_QUERY_DIALOG); +} + +// The isXXX() come from the Perl headers. +#define FILENAME_IS_ABSOLUTE(n) \ + (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\') + +static TBool IsInPerl(TFileName aFileName) +{ + TInt offset = aFileName.FindF(KScriptPrefix); + return ((offset == 0 && // \foo + aFileName[0] == '\\') + || + (offset == 2 && // x:\foo + FILENAME_IS_ABSOLUTE(aFileName))); +} + +static TBool IsInInbox(TFileName aFileName) +{ + TInt offset = aFileName.FindF(KInboxPrefix); + return ((offset == 0 && // \foo + aFileName[0] == '\\') + || + (offset == 2 && // x:\foo + FILENAME_IS_ABSOLUTE(aFileName))); +} + +static TBool IsPerlModule(TParsePtrC aParsed) +{ + return aParsed.Ext().CompareF(_L(".pm")) == 0; +} + +static TBool IsPerlScript(TParsePtrC aParsed) +{ + return aParsed.Ext().CompareF(_L(".pl")) == 0; +} + +static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst) +{ + TBool proceed = ETrue; + TMessageBuffer message; + + message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst); + if (OkCancelDialogL(message)) { + message.Format(_L("Install as %S?"), &aDst); + if (OkCancelDialogL(message)) { + if (BaflUtils::FileExists(aFs, aDst)) { + message.Format(_L("Replace old %S?"), &aDst); + if (!OkCancelDialogL(message)) + proceed = EFalse; + } + if (proceed) { + // Create directory? + TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst); + if (err == KErrNone) { + message.Format(_L("Installed %S"), &aDst); + ConfirmationNoteL(message); + } + else { + message.Format(_L("Failure %d installing %S"), err, &aDst); + WarningNoteL(message); + } + } + } + } +} + +static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn) +{ + aFn.SetMax(); + TInt m = aFn.MaxLength(); + TInt n = aPeekBuffer.Length(); + TInt i = 0; + TInt j = aOff; + + aFn.SetMax(); + // The following is a little regular expression + // engine that matches Perl package names. + if (j < n && isSPACE(aPeekBuffer[j])) { + while (j < n && isSPACE(aPeekBuffer[j])) j++; + if (j < n && isALPHA(aPeekBuffer[j])) { + while (j < n && isALNUM(aPeekBuffer[j])) { + while (j < n && + isALNUM(aPeekBuffer[j]) && + i < m) + aFn[i++] = aPeekBuffer[j++]; + if (j + 1 < n && + aPeekBuffer[j ] == ':' && + aPeekBuffer[j + 1] == ':' && + i < m) { + aFn[i++] = '\\'; + j += 2; + if (j < n && + isALPHA(aPeekBuffer[j])) { + while (j < n && + isALNUM(aPeekBuffer[j]) && + i < m) + aFn[i++] = aPeekBuffer[j++]; + } + } + } + while (j < n && isSPACE(aPeekBuffer[j])) j++; + if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) { + aFn.SetLength(i); + aFn.Append(_L(".pm")); + return ETrue; + } + } + } + return EFalse; +} + +static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive) +{ + TInt offset = aPeekBuffer.Find(_L8("package")); + if (offset != KErrNotFound) { + const TInt KPackageLen = 7; + TFileName q; + + if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q)) + return; + + TFileName8 p; + p.Copy(aDrive.Drive()); + p.Append(KModulePrefix); + + aGuess.SetMax(); + if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) { + TInt i = 0, j; + + for (j = 0; j < p.Length(); j++) + aGuess[i++] = p[j]; + aGuess[i++] = '\\'; + for (j = 0; j < q.Length(); j++) + aGuess[i++] = q[j]; + aGuess.SetLength(i); + } + else + aGuess.SetLength(0); + } +} + +static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer) +{ + return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 && + aPeekBuffer.Find(_L8("perl")) != KErrNotFound; +} + +static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs) +{ + TFileName aDst; + TPtrC drive = aDrive.Drive(); + TPtrC namext = aFile.NameAndExt(); + + aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext); + if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) { + aDst.SetLength(0); + if (IsPerlModule(aDst)) + GuessPerlModule(aDst, aPeekBuffer, aDrive); + } + if (aDst.Length() > 0) { + CopyFromInboxL(aFs, aSrc, aDst); + return ETrue; + } + + return EFalse; +} + +static void DoRunScriptL(TFileName aScriptName) +{ + CPerlBase* perl = CPerlBase::NewInterpreterLC(); + TRAPD(error, perl->RunScriptL(aScriptName)); + if (error != KErrNone) { + TMessageBuffer message; + message.Format(_L("Error %d"), error); + YesNoDialogL(message); + } + CleanupStack::PopAndDestroy(perl); +} + +static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer) +{ + TBool isModule = EFalse; + + if (IsInPerl(aScriptName) && + (IsPerlScript(aScriptName) || + (isModule = IsPerlModule(aScriptName)) || + LooksLikePerlL(aPeekBuffer))) { + TMessageBuffer message; + + if (isModule) + message.Format(_L("Really run module %S?"), &aScriptName); + else + message.Format(_L("Run %S?"), &aScriptName); + if (YesNoDialogL(message)) + DoRunScriptL(aScriptName); + + return ETrue; + } + + return EFalse; +} + +void CPerlAppUi::InstallOrRunL(const TFileName& aFileName) +{ + TParse aFile; + TParse aDrive; + TMessageBuffer message; + + aFile.Set(aFileName, NULL, NULL); + if (FILENAME_IS_ABSOLUTE(aFileName)) { + aDrive.Set(aFileName, NULL, NULL); + } else { + TFileName appName = + CEikonEnv::Static()->EikAppUi()->Application()->AppFullName(); + aDrive.Set(appName, NULL, NULL); + } + if (!iFs) + iFs = &CEikonEnv::Static()->FsSession(); + RFile f; + TInt err = f.Open(*iFs, aFileName, EFileRead); + if (err == KErrNone) { + TPeekBuffer aPeekBuffer; + err = f.Read(aPeekBuffer); + f.Close(); // Release quickly. + if (err == KErrNone) { + if (!(IsInInbox(aFileName) ? + InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) : + RunStuffL(aFileName, aPeekBuffer))) { + message.Format(_L("Failed for file %S"), &aFileName); + WarningNoteL(message); + } + } else { + message.Format(_L("Error %d reading %S"), err, &aFileName); + WarningNoteL(message); + } + } else { + message.Format(_L("Error %d opening %S"), err, &aFileName); + WarningNoteL(message); + } + if (iDoorObserver) + delete CEikonEnv::Static()->EikAppUi(); + else + Exit(); +} + +void CPerlAppUi::OpenFileL(const TDesC& aFileName) +{ + InstallOrRunL(aFileName); + return; +} + +TBool CPerlAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */) +{ + return aCommand == EApaCommandOpen ? ETrue : EFalse; +} + +void CPerlAppUi::SetFs(const RFs& aFs) +{ + iFs = (RFs*) &aFs; +} + +void CPerlAppUi::HandleCommandL(TInt aCommand) +{ + TMessageBuffer message; + + switch(aCommand) + { + case EEikCmdExit: + case EAknSoftkeyExit: + Exit(); + break; + case EPerlAppCommandAbout: + { + message.Format(KAboutFormat, + PERL_REVISION, + PERL_VERSION, + PERL_SUBVERSION, + PERL_SYMBIANPORT_MAJOR, + PERL_SYMBIANPORT_MINOR, + PERL_SYMBIANPORT_PATCH, + &KFlavor, + PERL_SYMBIANSDK_MAJOR, + PERL_SYMBIANSDK_MINOR + ); + InformationNoteL(message); + } + break; + case EPerlAppCommandTime: + { + CPerlBase* perl = CPerlBase::NewInterpreterLC(); + const char *const argv[] = + { "perl", "-le", + "print 'Running in ', $^O, \"\\n\", scalar localtime" }; + perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0); + CleanupStack::PopAndDestroy(perl); + } + break; + case EPerlAppCommandRunFile: + { + InformationNoteL(message); + TFileName aScriptUtf16; + if (AknCommonDialogs::RunSelectDlgLD(aScriptUtf16, + R_MEMORY_SELECTION_DIALOG)) + DoRunScriptL(aScriptUtf16); + } + break; + case EPerlAppCommandOneLiner: + { + _LIT(prompt, "Oneliner:"); + if (TextQueryDialogL(prompt, iOneLiner, KPerlAppOneLinerSize)) { + const TUint KPerlAppUtf8Multi = 3; + TBuf8<KPerlAppUtf8Multi * KPerlAppOneLinerSize> utf8; + + CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8, iOneLiner); + CPerlBase* perl = CPerlBase::NewInterpreterLC(); + int argc = 3; + char **argv = (char**) malloc(argc * sizeof(char *)); + User::LeaveIfNull(argv); + + TCleanupItem argvCleanupItem = TCleanupItem(free, argv); + CleanupStack::PushL(argvCleanupItem); + argv[0] = (char *) "perl"; + argv[1] = (char *) "-le"; + argv[2] = (char *) utf8.PtrZ(); + perl->ParseAndRun(argc, argv); + CleanupStack::PopAndDestroy(2, perl); + } + } + break; + case EPerlAppCommandCopyright: + { + message.Format(KCopyrightFormat); + InformationNoteL(message); + } + break; + + default: + Panic(EPerlAppCommandUnknown); + break; + } +} + +CPerlAppView* CPerlAppView::NewL(const TRect& aRect) +{ + CPerlAppView* self = CPerlAppView::NewLC(aRect); + CleanupStack::Pop(self); + return self; +} + +CPerlAppView* CPerlAppView::NewLC(const TRect& aRect) +{ + CPerlAppView* self = new (ELeave) CPerlAppView; + CleanupStack::PushL(self); + self->ConstructL(aRect); + return self; +} + +void CPerlAppView::ConstructL(const TRect& aRect) +{ + CreateWindowL(); + SetRect(aRect); + ActivateL(); +} + +void CPerlAppView::Draw(const TRect& /*aRect*/) const +{ + CWindowGc& gc = SystemGc(); + TRect rect = Rect(); + gc.Clear(rect); +} + +CApaDocument* CPerlAppApplication::CreateDocumentL() +{ + CPerlAppDocument* document = new (ELeave) CPerlAppDocument(*this); + return document; +} + +CEikAppUi* CPerlAppDocument::CreateAppUiL() +{ + CPerlAppUi* appui = new (ELeave) CPerlAppUi(); + return appui; +} + +CFileStore* CPerlAppDocument::OpenFileL(TBool /* aDoOpen */, const TDesC& aFileName, RFs& aFs) +{ + CPerlAppUi* appui = + STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi()); + appui->SetFs(aFs); + appui->OpenFileL(aFileName); + return NULL; +} + +EXPORT_C CApaApplication* NewApplication() +{ + return new CPerlAppApplication; +} + +GLDEF_C TInt E32Dll(TDllReason /*aReason*/) +{ + return KErrNone; +} + diff --git a/symbian/PerlApp.h b/symbian/PerlApp.h new file mode 100644 index 0000000000..37a02f2502 --- /dev/null +++ b/symbian/PerlApp.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The PerlApp application is licensed under the same terms as Perl itself. */ + +#ifndef __PerlApp_h__ +#define __PerlApp_h__ + +#include <aknapp.h> +#include <aknappui.h> +#include <akndoc.h> +#include <coecntrl.h> +#include <f32file.h> + +class CPerlAppDocument : public CAknDocument +{ + public: + CPerlAppDocument(CEikApplication& aApp):CAknDocument(aApp) {;} + CFileStore* OpenFileL(TBool aDoOpen, const TDesC& aFilename, RFs& aFs); + private: // from CEikDocument + CEikAppUi* CreateAppUiL(); +}; + +class CPerlAppApplication : public CAknApplication +{ + private: + CApaDocument* CreateDocumentL(); + TUid AppDllUid() const; +}; + +const TUint KPerlAppOneLinerSize = 80; + +class CPerlAppView; + +class CPerlAppUi : public CAknAppUi +{ + public: + void ConstructL(); + ~CPerlAppUi(); + void HandleCommandL(TInt aCommand); + void OpenFileL(const TDesC& aFileName); + TBool ProcessCommandParametersL(TApaCommand aCommand, TFileName& aDocumentName, const TDesC8& aTail); + void InstallOrRunL(const TFileName& aFileName); + void SetFs(const RFs& aFs); + private: + CPerlAppView* iAppView; + RFs* iFs; + TBuf<KPerlAppOneLinerSize> iOneLiner; +}; + +class CPerlAppView : public CCoeControl +{ + public: + static CPerlAppView* NewL(const TRect& aRect); + static CPerlAppView* NewLC(const TRect& aRect); + void Draw(const TRect& aRect) const; + private: + void ConstructL(const TRect& aRect); +}; + +#endif // __PerlApp_h__ diff --git a/symbian/PerlApp.hrh b/symbian/PerlApp.hrh new file mode 100644 index 0000000000..3b0f23d79a --- /dev/null +++ b/symbian/PerlApp.hrh @@ -0,0 +1,17 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The PerlApp application is licensed under the same terms as Perl itself. */ + +#ifndef __PerlApp_HRH__ +#define __PerlApp_HRH__ + +enum TPerlIds +{ + EPerlAppCommandAbout = 1024, // start value must not be 0 + EPerlAppCommandTime = 1025, + EPerlAppCommandRunFile = 1026, + EPerlAppCommandOneLiner = 1027, + EPerlAppCommandCopyright = 1028 // no comma here +}; + +#endif // __PerlApp_HRH__ diff --git a/symbian/PerlApp.rss b/symbian/PerlApp.rss new file mode 100644 index 0000000000..c352c528db --- /dev/null +++ b/symbian/PerlApp.rss @@ -0,0 +1,141 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The PerlApp application is licensed under the same terms as Perl itself. */ + +NAME PERL + +#include <eikon.rh> +#include <avkon.rh> +#include <avkon.rsg> + +#include "PerlApp.hrh" + +RESOURCE RSS_SIGNATURE +{ +} + +RESOURCE TBUF r_default_document_name +{ + buf = ""; +} + +RESOURCE EIK_APP_INFO +{ + menubar = r_Perl_menubar; + cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; +} + + +RESOURCE MENU_BAR r_Perl_menubar +{ + titles = { + MENU_TITLE + { + menu_pane = r_Perl_menu; + } + }; +} + + +RESOURCE MENU_PANE r_Perl_menu +{ + items = { + MENU_ITEM { + command = EPerlAppCommandAbout; + txt = "About"; + }, + MENU_ITEM { + command = EPerlAppCommandTime; + txt = "Time"; + }, + MENU_ITEM { + command = EPerlAppCommandRunFile; + txt = "Run"; + }, + MENU_ITEM { + command = EPerlAppCommandOneLiner; + txt = "Oneliner"; + }, + MENU_ITEM { + command = EPerlAppCommandCopyright; + txt = "Copyright"; + } + }; +} + +RESOURCE DIALOG r_ok_cancel_dialog +{ + flags = EEikDialogFlagWait | EEikDialogFlagCbaButtons; + buttons = R_AVKON_SOFTKEYS_OK_CANCEL; + items = { + DLG_LINE + { + type = EAknCtNote; + id = EGeneralNote; + control = AVKON_NOTE + { + layout = EGeneralLayout; + }; + } + }; +} + +RESOURCE DIALOG r_yes_no_dialog +{ + flags = EEikDialogFlagWait | EEikDialogFlagCbaButtons; + buttons = R_AVKON_SOFTKEYS_YES_NO; + items = { + DLG_LINE + { + type = EAknCtNote; + id = EGeneralNote; + control = AVKON_NOTE + { + layout = EGeneralLayout; + }; + } + }; +} + +RESOURCE DIALOG r_text_query_dialog +{ + flags = EGeneralQueryFlags; + buttons = R_AVKON_SOFTKEYS_OK_CANCEL; + items = { + DLG_LINE + { + type = EAknCtQuery; + id = EGeneralQuery; + control = AVKON_DATA_QUERY + { + layout = EDataLayout; + control = EDWIN {}; + }; + } + }; +} + +RESOURCE AVKON_LIST_QUERY r_list_query_dialog +{ + flags = EGeneralQueryFlags; + softkeys = R_AVKON_SOFTKEYS_OK_CANCEL; + items = { + DLG_LINE + { + type = EAknCtListQueryControl; + id = EListQueryControl; + control = AVKON_LIST_QUERY_CONTROL + { + listtype = EAknCtSinglePopupMenuListBox; + }; + } + }; +} + +#include <CommonDialogs.hrh> +#include <CommonDialogs.rh> + +RESOURCE MEMORYSELECTIONDIALOG r_memory_selection_dialog +{ +} + diff --git a/symbian/PerlAppAif.rss b/symbian/PerlAppAif.rss new file mode 100644 index 0000000000..fa4d42b0e1 --- /dev/null +++ b/symbian/PerlAppAif.rss @@ -0,0 +1,21 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The PerlApp application is licensed under the same terms as Perl itself. */ + +#include <aiftool.rh> + +RESOURCE AIF_DATA +{ + app_uid = 0x102015F6; + embeddability = KAppEmbeddable; + hidden = KAppNotHidden; + launch = KAppLaunchInForeground; + newfile = KAppDoesNotSupportNewFile; + datatype_list = { + DATATYPE + { + priority = EDataTypePriorityNormal; + type = "x-application/x-perl"; + } + }; + } diff --git a/symbian/PerlBase.cpp b/symbian/PerlBase.cpp new file mode 100644 index 0000000000..31fe012f80 --- /dev/null +++ b/symbian/PerlBase.cpp @@ -0,0 +1,409 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The CPerlBase class is licensed under the same terms as Perl itself. */ + +/* See PerlBase.pod for documentation. */ + +#define PERLBASE_CPP + +#include <e32cons.h> +#include <e32keys.h> +#include <utf.h> + +#include "PerlBase.h" + +const TUint KPerlConsoleBufferMaxTChars = 0x0200; +const TUint KPerlConsoleNoPos = 0xffff; + +CPerlBase::CPerlBase() +{ +} + +EXPORT_C void CPerlBase::Destruct() +{ + iState = EPerlDestroying; + if (iConsole) { + iConsole->Printf(_L("[Any key to continue]")); + iConsole->Getch(); + } + if (iPerl) { + (void)perl_destruct(iPerl); + perl_free(iPerl); + iPerl = NULL; + PERL_SYS_TERM(); + } + if (iConsole) { + delete iConsole; + iConsole = NULL; + } + if (iConsoleBuffer) { + free(iConsoleBuffer); + iConsoleBuffer = NULL; + } +#ifdef PERL_GLOBAL_STRUCT + if (iVars) { + PerlInterpreter* my_perl = NULL; + free_global_struct(iVars); + iVars = NULL; + } +#endif +} + +CPerlBase::~CPerlBase() +{ + Destruct(); +} + +EXPORT_C CPerlBase* CPerlBase::NewInterpreterL(TBool aCloseStdlib, + void (*aStdioInitFunc)(void*), + void *aStdioInitCookie) +{ + CPerlBase* self = + CPerlBase::NewInterpreterLC(aCloseStdlib, + aStdioInitFunc, + aStdioInitCookie); + CleanupStack::Pop(self); + return self; +} + +EXPORT_C CPerlBase* CPerlBase::NewInterpreterLC(TBool aCloseStdlib, + void (*aStdioInitFunc)(void*), + void *aStdioInitCookie) +{ + CPerlBase* self = new (ELeave) CPerlBase; + CleanupStack::PushL(self); + self->iCloseStdlib = aCloseStdlib; + self->iStdioInitFunc = aStdioInitFunc; + self->iStdioInitCookie = aStdioInitCookie; + self->ConstructL(); + PERL_APPCTX_SET(self); + return self; +} + +static int _console_stdin(void* cookie, char* buf, int n) +{ + return ((CPerlBase*)cookie)->ConsoleRead(0, buf, n); +} + +static int _console_stdout(void* cookie, const char* buf, int n) +{ + return ((CPerlBase*)cookie)->ConsoleWrite(1, buf, n); +} + +static int _console_stderr(void* cookie, const char* buf, int n) +{ + return ((CPerlBase*)cookie)->ConsoleWrite(2, buf, n); +} + +void CPerlBase::StdioRewire(void *arg) { + _REENT->_sf[0]._cookie = (void*)this; + _REENT->_sf[0]._read = &_console_stdin; + _REENT->_sf[0]._write = 0; + _REENT->_sf[0]._seek = 0; + _REENT->_sf[0]._close = 0; + + _REENT->_sf[1]._cookie = (void*)this; + _REENT->_sf[1]._read = 0; + _REENT->_sf[1]._write = &_console_stdout; + _REENT->_sf[1]._seek = 0; + _REENT->_sf[1]._close = 0; + + _REENT->_sf[2]._cookie = (void*)this; + _REENT->_sf[2]._read = 0; + _REENT->_sf[2]._write = &_console_stderr; + _REENT->_sf[2]._seek = 0; + _REENT->_sf[2]._close = 0; +} + +void CPerlBase::ConstructL() +{ + iState = EPerlNone; +#ifdef PERL_GLOBAL_STRUCT + PerlInterpreter *my_perl = 0; + iVars = init_global_struct(); + User::LeaveIfNull(iVars); +#endif + iPerl = perl_alloc(); + User::LeaveIfNull(iPerl); + iState = EPerlAllocated; + perl_construct(iPerl); // returns void + if (!iStdioInitFunc) { + iConsole = + Console::NewL(_L("Perl Console"), + TSize(KConsFullScreen, KConsFullScreen)); + iConsoleBuffer = + (TUint16*)malloc(sizeof(TUint) * + KPerlConsoleBufferMaxTChars); + User::LeaveIfNull(iConsoleBuffer); + iConsoleUsed = 0; +#ifndef USE_PERLIO + iStdioInitFunc = &StdioRewire; +#endif + } + if (iStdioInitFunc) + iStdioInitFunc(iStdioInitCookie); + iReadFunc = NULL; + iWriteFunc = NULL; + iState = EPerlConstructed; +} + +EXPORT_C PerlInterpreter* CPerlBase::GetInterpreter() +{ + return (PerlInterpreter*) iPerl; +} + +#ifdef PERL_MINIPERL +static void boot_DynaLoader(pTHX_ CV* cv) { } +#else +EXTERN_C void boot_DynaLoader(pTHX_ CV* cv); +#endif + +static void xs_init(pTHX) +{ + dXSUB_SYS; + newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); +} + +EXPORT_C TInt CPerlBase::RunScriptL(const TDesC& aFileName, + int argc, + char **argv, + char *envp[]) { + TBuf8<KMaxFileName> scriptUtf8; + TInt error; + error = CnvUtfConverter::ConvertFromUnicodeToUtf8(scriptUtf8, aFileName); + User::LeaveIfError(error); + char *filename = (char*)scriptUtf8.PtrZ(); + struct stat st; + if (stat(filename, &st) == -1) + return KErrNotFound; + if (argc < 2) + return KErrGeneral; /* Anything better? */ + char **Argv = (char**)malloc(argc * sizeof(char*)); + User::LeaveIfNull(Argv); + TCleanupItem ArgvCleanupItem = TCleanupItem(free, Argv); + CleanupStack::PushL(ArgvCleanupItem); + Argv[0] = "perl"; + if (argv && argc > 2) + for (int i = 2; i < argc - 1; i++) + Argv[i] = argv[i]; + Argv[argc - 1] = filename; + error = this->ParseAndRun(argc, Argv, envp); + CleanupStack::PopAndDestroy(Argv); + Argv = 0; + return error == 0 ? KErrNone : KErrGeneral; +} + + +EXPORT_C int CPerlBase::Parse(int argc, char *argv[], char *envp[]) +{ + if (iState == EPerlConstructed) { + const char* const NullArgv[] = { "perl", "-e", "0" }; + if (argc == 0 || argv == 0) { + argc = 3; + argv = (char**) NullArgv; + } + PERL_SYS_INIT(&argc, &argv); + int parsed = perl_parse(iPerl, xs_init, argc, argv, envp); + if (parsed == 0) + iState = EPerlParsed; + return parsed; + } else + return -1; +} + +EXPORT_C void CPerlBase::SetupExit() +{ + if (iState == EPerlParsed) { + diTHX; + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + // PL_perl_destruct level of 2 would be nice but + // it causes "Unbalanced scopes" for some reason. + PL_perl_destruct_level = 1; + } +} + +EXPORT_C int CPerlBase::Run() +{ + if (iState == EPerlParsed) { + SetupExit(); + iState = EPerlRunning; + int ran = perl_run(iPerl); + iState = (ran == 0) ? EPerlSuccess : EPerlFailure; + return ran; + } else + return -1; +} + +EXPORT_C int CPerlBase::ParseAndRun(int argc, char *argv[], char *envp[]) +{ + int parsed = Parse(argc, argv, envp); + int ran = (parsed == 0) ? Run() : -1; + return ran; +} + +int CPerlBase::ConsoleReadLine() +{ + if (!iConsole) + return -EIO; + + TUint currX = KPerlConsoleNoPos; + TUint currY = KPerlConsoleNoPos; + TUint prevX = KPerlConsoleNoPos; + TUint prevY = KPerlConsoleNoPos; + TUint maxX = KPerlConsoleNoPos; + TUint offset = 0; + + for (;;) { + TKeyCode code = iConsole->Getch(); + + if (code == EKeyLineFeed || code == EKeyEnter) { + if (offset < KPerlConsoleBufferMaxTChars) { + iConsoleBuffer[offset++] = '\n'; + iConsole->Printf(_L("\n")); + iConsoleBuffer[offset++] = 0; + } + break; + } + else { + TBool doBackward = EFalse; + TBool doBackspace = EFalse; + + prevX = currX; + prevY = currY; + if (code == EKeyBackspace) { + if (offset > 0) { + iConsoleBuffer[--offset] = 0; + doBackward = ETrue; + doBackspace = ETrue; + } + } + else if (offset < KPerlConsoleBufferMaxTChars) { + TChar ch = TChar(code); + + if (ch.IsPrint()) { + iConsoleBuffer[offset++] = (unsigned short)code; + iConsole->Printf(_L("%c"), code); + } + } + currX = iConsole->WhereX(); + currY = iConsole->WhereY(); + if (maxX == KPerlConsoleNoPos && prevX != KPerlConsoleNoPos && + prevY != KPerlConsoleNoPos && currY == prevY + 1) + maxX = prevX; + if (doBackward) { + if (currX > 0) + iConsole->SetPos(currX - 1); + else if (currY > 0) + iConsole->SetPos(maxX, currY - 1); + if (doBackspace) { + TUint nowX = iConsole->WhereX(); + TUint nowY = iConsole->WhereY(); + iConsole->Printf(_L(" ")); /* scrub */ + iConsole->SetPos(nowX, nowY); + } + } + } + } + + return offset; +} + +int CPerlBase::ConsoleRead(const int fd, char* buf, int n) +{ + if (iReadFunc) + return iReadFunc(fd, buf, n); + + if (!iConsole) { + errno = EIO; + return -1; + } + + if (n < 0) { + errno = EINVAL; + return -1; + } + + if (n == 0) + return 0; + + TBuf8<4 * KPerlConsoleBufferMaxTChars> aBufferUtf8; + TBuf16<KPerlConsoleBufferMaxTChars> aBufferUtf16; + int length = ConsoleReadLine(); + int i; + + iConsoleUsed += length; + + aBufferUtf16.SetLength(length); + for (i = 0; i < length; i++) + aBufferUtf16[i] = iConsoleBuffer[i]; + aBufferUtf8.SetLength(4 * length); + + CnvUtfConverter::ConvertFromUnicodeToUtf8(aBufferUtf8, aBufferUtf16); + + char *pUtf8 = (char*)aBufferUtf8.PtrZ(); + int nUtf8 = aBufferUtf8.Size(); + if (nUtf8 > n) + nUtf8 = n; /* Potential data loss. */ +#ifdef PERL_SYMBIAN_CONSOLE_UTF8 + for (i = 0; i < nUtf8; i++) + buf[i] = pUtf8[i]; +#else + dTHX; + for (i = 0; i < nUtf8; i+= UTF8SKIP(pUtf8 + i)) { + unsigned long u = utf8_to_uvchr((U8*)(pUtf8 + i), 0); + if (u > 0xFF) { + iConsole->Printf(_L("(keycode > 0xFF)\n")); + buf[i] = 0; + return -1; + } + buf[i] = u; + } +#endif + if (nUtf8 < n) + buf[nUtf8] = 0; + return nUtf8; +} + +int CPerlBase::ConsoleWrite(const int fd, const char* buf, int n) +{ + if (iWriteFunc) + return iWriteFunc(fd, buf, n); + + if (!iConsole) { + errno = EIO; + return -1; + } + + if (n < 0) { + errno = EINVAL; + return -1; + } + + if (n == 0) + return 0; + + int wrote = 0; +#ifdef PERL_SYMBIAN_CONSOLE_UTF8 + dTHX; + if (is_utf8_string((U8*)buf, n)) { + for (int i = 0; i < n; i += UTF8SKIP(buf + i)) { + TChar u = utf8_to_uvchr((U8*)(buf + i), 0); + iConsole->Printf(_L("%c"), u); + wrote++; + } + } else { + iConsole->Printf(_L("(malformed utf8: ")); + for (int i = 0; i < n; i++) + iConsole->Printf(_L("%02x "), buf[i]); + iConsole->Printf(_L(")\n")); + } +#else + for (int i = 0; i < n; i++) { + iConsole->Printf(_L("%c"), buf[i]); + } + wrote = n; +#endif + iConsoleUsed += wrote; + return n; +} + diff --git a/symbian/PerlBase.h b/symbian/PerlBase.h new file mode 100644 index 0000000000..f6765fbed2 --- /dev/null +++ b/symbian/PerlBase.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The CPerlBase class is licensed under the same terms as Perl itself. */ + +/* See PerlBase.pod for documentation. */ + +#ifndef __PerlBase_h__ +#define __PerlBase_h__ + +#include <e32base.h> + +#if !defined(PERL_MINIPERL) && !defined(PERL_PERL) +# ifndef PERL_IMPLICIT_CONTEXT +# define PERL_IMPLICIT_CONTEXT +# endif +# ifndef PERL_MULTIPLICITY +# define PERL_MULTIPLICITY +# endif +# ifndef PERL_GLOBAL_STRUCT +# define PERL_GLOBAL_STRUCT +# endif +# ifndef PERL_GLOBAL_STRUCT_PRIVATE +# define PERL_GLOBAL_STRUCT_PRIVATE +# endif +#endif + +#include "EXTERN.h" +#include "perl.h" + +typedef enum { + EPerlNone, + EPerlAllocated, + EPerlConstructed, + EPerlParsed, + EPerlRunning, + EPerlTerminated, + EPerlPaused, + EPerlSuccess, + EPerlFailure, + EPerlDestroying +} TPerlState; + +class PerlConsole; + +class CPerlBase : public CBase +{ + public: + CPerlBase(); + IMPORT_C virtual ~CPerlBase(); + IMPORT_C static CPerlBase* NewInterpreterL(TBool iCloseStdlib = ETrue, + void (*aStdioInitFunc)(void*) = NULL, + void *aStdioInitCookie = NULL); + IMPORT_C static CPerlBase* NewInterpreterLC(TBool iCloseStdlib = ETrue, + void (*aStdioInitFunc)(void*) = NULL, + void *aStdioInitCookie = NULL); + IMPORT_C TInt RunScriptL(const TDesC& aFileName, int argc = 2, char **argv = NULL, char *envp[] = NULL); + IMPORT_C int Parse(int argc = 0, char *argv[] = NULL, char *envp[] = NULL); + IMPORT_C void SetupExit(); + IMPORT_C int Run(); + IMPORT_C int ParseAndRun(int argc = 0, char *argv[] = 0, char *envp[] = 0); + IMPORT_C void Destruct(); + + IMPORT_C PerlInterpreter* GetInterpreter(); + + // These two really should be private but when not using PERLIO + // certain C callback functions of STDLIB need to be able to call + // these. In general, all the console related functionality is + // intentionally hidden and underdocumented. + int ConsoleRead(const int fd, char* buf, int n); + int ConsoleWrite(const int fd, const char* buf, int n); + + // Having these public does not feel right, but maybe someone needs + // to do creative things with them. + int (*iReadFunc)(const int fd, char *buf, int n); + int (*iWriteFunc)(const int fd, const char *buf, int n); + + protected: + PerlInterpreter* iPerl; +#ifdef PERL_GLOBAL_STRUCT + struct perl_vars* iVars; +#else + void* iAppCtx; +#endif + TPerlState iState; + + private: + + void ConstructL(); + CConsoleBase* iConsole; /* The screen. */ + TUint16* iConsoleBuffer; /* The UTF-16 characters. */ + TUint iConsoleUsed; /* How many in iConsoleBuffer. */ + TBool iCloseStdlib; /* Close STDLIB on exit? */ + + void (*iStdioInitFunc)(void *); + void* iStdioInitCookie; + + int ConsoleReadLine(); + void StdioRewire(void*); +}; + +#define diTHX PerlInterpreter* my_perl = iPerl +#define diVAR struct perl_vars* my_vars = iVars + +#ifdef PERL_GLOBAL_STRUCT +# define PERL_APPCTX_SET(c) ((c)->iVars->Gappctx = (c)) +#else +# define PERL_APPCTX_SET(c) (PL_appctx = (c)) +#endif + +#undef Copy +#undef CopyD /* For symmetry, not for Symbian reasons. */ +#undef New +#define PerlCopy(s,d,n,t) (MEM_WRAP_CHECK(n,t), (void)memcpy((char*)(d),(char*)(s), (n) * sizeof(t))) +#define PerlCopyD(s,d,n,t) (MEM_WRAP_CHECK(n,t), memcpy((char*)(d),(char*)(s), (n) * sizeof(t))) +#define PerlNew(x,v,n,t) (v = (MEM_WRAP_CHECK(n,t), (t*)safemalloc((MEM_SIZE)((n)*sizeof(t))))) + +#endif /* #ifndef __PerlBase_h__ */ + diff --git a/symbian/PerlBase.pod b/symbian/PerlBase.pod new file mode 100644 index 0000000000..265e2d6d8b --- /dev/null +++ b/symbian/PerlBase.pod @@ -0,0 +1,202 @@ +=head1 NAME + +CPerlBase - a base class encapsulating a Perl interpreter + +=head1 SYNOPSIS + + // in your App.mmp + USERINCLUDE \symbian\perl\x.y.z\include + LIBRARY perlXYZ.lib + + // in your App + #include "PerlBase.h" // includes also EXTERN.h and perl.h + CPerlBase* perl = CPerlBase::NewInterpreterLC(); + ... + delete perl; + +=head1 DESCRIPTION + +CPerlBase is a simple Symbian C++ class that wraps a Perl +interpreter; its creation, use, and destroying. To understand +what this is doing, and how to use the interpreter, a fair knowledge +of L<perlapi>, L<perlguts>, and L<perlembed> is recommended. + +One useful thing CPerlBase does compared with just using the raw +Perl C API is that it redirects the "std streams" (STDOUT et alia) +to a text console implementation which while being very basic +is marginally more usable than the Symbian basic text console. + +=head2 The Basics + +=over 4 + +=item * + +CPerlBase* NewInterpreterL(); + +The constructor that does not keep the object in the Symbian "cleanup stack". +perl_alloc() and perl_construct() are called behind the curtains. + +Accepts the same arguments as NewInterpreterLC(). + +=item * + +CPerlBase* NewInterpreterLC(); + +The constructor that keeps the object in the Symbian "cleanup stack". +perl_alloc() and perl_construct() are called behind the curtains. + +Can have three arguments: + +=over 8 + +=item * + +TBool aCloseStdlib = ETrue + +Should a CPerlBase close the Symbian POSIX STDLIB when closing down. +Good for one-shot script execution, probably less good for longer term +embedded interpreter. + +=item * + +void (*aStdioInitFunc)(void*) = NULL + +If set, called with aStdioInitCookie, and the default console is +not created. You may want to set the iReadFunc() and iWriteFunc(). + +=item * + +void *aStdioInitCookie = NULL + +Used as the argument for aStdioInitFunc(). + +=back + +=item * + +void Destroy(); + +The destructor of the interpreter. The class destructor calls +first this and then the Symbian CloseSTDLIB(). + +perl_destruct(), perl_free(), and PERL_SYS_TERM() are called +behind the curtains. + +=back + +=head2 Utility functions + +=over 4 + +=item * + +int Parse(int argc = 0, char *argv[] = 0, char *envp[] = 0); + +Prepare an interpreter for executing by parsing input as if a C main() +had been called. For example to parse a script, use argc of 2 and argv +of { "perl", script_name }. + +All arguments are optional: in case either argc or argv are zero, +argc of 3 and argv of { "perl", "-e", "0" } is assumed. + +PERL_SYS_INIT() and perl_parse() are called behind the curtains. + +Note that a call to Parse() is required before Run(). + +Returns zero if parsing was successful, non-zero if not (and the stderr +will get the error). + +=item * + +int Run() + +Start executing an interpeter. A Parse() must have been called before +a Run(): use 3 and { "", "-e", 0 } if you do not have an argv. + +Note that a call to Parse() is required before Run(). + +perl_run() is called behind the curtains. + +Returns zero if execution was successful, non-zero if not (and the stderr +will get the error). + +=item * + +int ParseAndRun(int argc, char *argv[], char *envp[]); + +Combined Parse() and Run(). The Run() is not run if the Parse() fails. + +Returns zero if parsing and execution were successful, non-zero if not. + +=item * + +TInt RunScriptL(TDesC& aFileName, int argc, char **argv, char *envp[]) + +Like ParseAndRun() but works for Symbian filenames (UTF-16LE). +The UTF-8 version of aFileName is always argv[argc-1], and argv[0] +is always "perl". + +=head2 Macros + +=over 4 + +=item * + +diTHX + +Set up my_perl from the current object (like dTHX). + +=item * + +diVAR + +Set up my_vars from the current object (like dVAR). + +=back + +=head2 Extending CPerlBase (subclassing, deriving from) + +Note that it probably isn't worth the trouble to try to wrap the +whole, rather large, Perl C API into a C++ API. Just use the C API. + +The protected members of the class are: + +=over 4 + +=item * + +PerlInterpreter* iPerl + +The Perl interpreter. + +=item * + +struct perl_vars* iVars + +The global variables of the interpreter. + +=item * + +TPerlState iState + +The state of the Perl interpreter. TPerlState is one of EPerlNone, +EPerlAllocated, EPerlConstructed, EPerlParsed, EPerlRunning, +EPerlTerminated, EPerlPaused (these two are currently unused +but in the future they might be used to indicate that the interpreter +was stopped either non-resumably or resumably for some reason), +EPerlSuccess (perl_run() succeeded), EPerlFailure (perl_run() failed), +EPerlDestroying. + +=back + +=head1 COPYRIGHT + +Copyright (c) 2004-2005 Nokia. All rights reserved. + +=head1 LICENSE + +The CPerlBase class is licensed under the same terms as Perl itself. + +=cut + diff --git a/symbian/PerlRecog.cpp b/symbian/PerlRecog.cpp new file mode 100644 index 0000000000..d2db54491b --- /dev/null +++ b/symbian/PerlRecog.cpp @@ -0,0 +1,57 @@ +/* Copyright (c) 2004-2005 Nokia. All rights reserved. */ + +/* The PerlRecog application is licensed under the same terms as Perl itself. */ + +#include <apmrec.h> +#include <apmstd.h> +#include <f32file.h> + +const TUid KUidPerlRecog = { 0x102015F7 }; +_LIT8(KPerlMimeType, "x-application/x-perl"); +_LIT8(KPerlSig, "#!/usr/bin/perl"); +const TInt KPerlSigLen = 15; + +class CApaPerlRecognizer : public CApaDataRecognizerType { + public: + CApaPerlRecognizer():CApaDataRecognizerType(KUidPerlRecog, EHigh) { + iCountDataTypes = 1; + } + virtual TUint PreferredBufSize() { return KPerlSigLen; } + virtual TDataType SupportedDataTypeL(TInt /* aIndex */) const { + return TDataType(KPerlMimeType); + } + private: + virtual void DoRecognizeL(const TDesC& aName, const TDesC8& aBuffer); +}; + +void CApaPerlRecognizer::DoRecognizeL(const TDesC& aName, const TDesC8& aBuffer) +{ + iConfidence = ENotRecognized; + + if (aBuffer.Length() >= KPerlSigLen && + aBuffer.Left(KPerlSigLen).Compare(KPerlSig) == 0) { + iConfidence = ECertain; + iDataType = TDataType(KPerlMimeType); + } else { + TParsePtrC p(aName); + + if ((p.Ext().CompareF(_L(".pl")) == 0) || + (p.Ext().CompareF(_L(".pm")) == 0)) { + iConfidence = ECertain; + iDataType = TDataType(KPerlMimeType); + } + } +} + +EXPORT_C CApaDataRecognizerType* CreateRecognizer() +{ + return new CApaPerlRecognizer; +} + +GLDEF_C TInt E32Dll(TDllReason /* aReason */) +{ + return KErrNone; +} + + + diff --git a/symbian/PerlRecog.mmp b/symbian/PerlRecog.mmp new file mode 100644 index 0000000000..6850103b5b --- /dev/null +++ b/symbian/PerlRecog.mmp @@ -0,0 +1,9 @@ +TARGET PerlRecog.mdl +TARGETTYPE mdl +UID 0x10003A19 0x102015F7 +TARGETPATH \system\recogs +SOURCE PerlRecog.cpp +USERINCLUDE . +SYSTEMINCLUDE \epoc32\include +LIBRARY euser.lib efsrv.lib apmime.lib + diff --git a/symbian/README b/symbian/README new file mode 100644 index 0000000000..95ed303851 --- /dev/null +++ b/symbian/README @@ -0,0 +1,20 @@ +The PerlApp* files are a demonstration application for the CPerlBase +class, which is defined and implemented by the PerlBase* files. +The rest of the files are part of the Symbian base port. + +All files are Copyright (c) Nokia, 2004-2005, all rights reserved, +and licensed under the same terms as Perl itself. + +Once the 'sdkinstall' make target has been run in the top level, +the PerlApp can be built using the standard Symbian way: + + bldmake bldfiles + abld build wins udeb + abld build thumb urel + +and then packaged into a SIS by: + + makesis PerlApp.pkg + +-- + diff --git a/symbian/TODO b/symbian/TODO new file mode 100644 index 0000000000..78dcd24630 --- /dev/null +++ b/symbian/TODO @@ -0,0 +1,150 @@ +=head1 BASE PORT + +=head2 Console + +- The Console only does "ASCII" input: e.g. pressing the "2" + key five times, "aaaaa", does not produce "ä" ("a diaeresis"), + but instead the "2" key rotates through "abc2abc2...". + This is a pity because the Console is actually capable of full + Unicode input and output (if you have the fonts, that is). You + can verify this by entering e.g. the euro character, which is + U+20AC, well beyond U+00FF. I don't know why the full repertoire + of the keyboard is not available. +- Enhance the console? (line editing, full x-y movement, history) +- The role of the console needs to be rethought: the best way + would be to have the console visible in the same screen as + the GUI elements (an "embedded console"?) + +=head2 Core Language + +- the $^E does not work +- select() does not work (not our fault) +- starting external application: what now (0.1.0) works is: + - system("app"); + - system("app&"); + - and those with arguments: + - system("app arg1 arg2") + - system("app arg1 arg2 &") + but remember that a Symbian process does get only argv[0] + and argv[1]: all the arguments of the application are passed + in as a single argument ("arg1 arg2" in the above) + What does not work: + - piped open, in either direction + - qx/backtick/` + - fork/wait (these unlikely to ever work as in POSIX) + - IO redirection or filename globbing in system() + (since there is no POSIX shell beneath) + What might work in future: + - exec() might be made to work + - Symbian::spawn("cmd args") returning a process id (what does Win32 do?) + - Symbian::waitpid($spawned_pid) + +=head2 Platform + +- in S60 1.2 (at least in 3650 Nokia 3650 v3.11) setjmp/longjmp is + fragile (see Symbian FAQ-0929), intensive debugging and fix needed +- in S60 2.x (at least in Nokia 6630 v4.03.11) launching scripts via + FExplorer does not open up the console + +=head2 Unicode + +- Symbian has Unicode filenames, and Unicode all over the place. +- Encode and the use of Symbian Unicode in general + tie into the overall usefulness of PerlIO. + +=head2 Portability + +- Slash versus Backslash: where does one need to use "\\"? + writing Perl applications, where can one get away with using "/" ? + +=head2 Build + +- make xsbuild.pl much more robust (for building external extensions) +- MakeMaker? Pure PM, PM + XS? +- currently the PerlApp UID is in both config.pl (hardwired) and + in makesis.pl (computed), this is quite error prone +- Enable building also under Cygwin? + +=head1 PACKAGING + +- subdivide perlext.sis? +- pm-stripper: strip pod and comments, while inserting the appropriate + #line commands to keep linenumbers in sync. Shaves off easily 50% + of the code, making install packages smaller. +- Get MakeMaker to create SIS packages? In non-Win32? +- Symbian has APIs for opening .zip files +- Investigate Autrijus Tang's PAR format + http://www.autrijus.org/par-intro/ +- "makeplsis" to wrap a script.pl or dir/script.pl as a stand-alone + application (and SIS): unshift the "application home" to @INC and + chdir to that, then run the script.pl (renamed as default.pl) + +=head1 PerlBase + +- review for proper Symbian coding practices + +=head1 PerlApp + +- In "Run" see how one could show also the file extensions. +- when autostarting also offer to display the file (via Notes?) + instead of installing/running it? +- Allow passing command line options to scripts being run? +- Add "OneLiner" menu item? (-e, -M) (requires a UI form) +- Terminate/Pause menu entries? +- review for proper Symbian coding practices + +=head1 CORE LIBRARIES + +- Fix Devel::PPPort (worth it?) (Note that there is D::PPP 3.x out by now) +- Fix Encode to not to have writeable data: seems to be tricky indeed + because of copious global non-const data. +- Verify that the modified File::Spec::Win32 does work in Symbian. + (File::Spec::Epoc does not seem to be relevant?) +- What does Cwd really do since the concept of cwd is a bit fuzzy in Symbian. +- What should Sys::Hostname return? GPRS? BT? WLAN? +- ByteLoader problem: byterun.c does not see VERSION and XS_VERSION. +- POSIX problem: STDLIB POSIX is not that POSIX. + +=head1 REGRESSION SUITE + +- how to run the standard test suite on a Symbian device? + +=head1 CPAN LIBRARIES + +- Include/Package more modules (or work harder on getting CPAN.pm working?) + (but note that lib/**/*.pm is 3.5 megabytes, probably not worth including + all of it, even after pm-stripping): + - libnet + - Bundle::CPAN + - Archive::Tar + - Compress::Zlib (zlib?) (there is builtin gz support) + - Term::ReadKey (useless?) + - Term::ReadLine (useless?) + - Bundle::LWP + - URI + - HTML::TagSet + - HTML::Parser + - HTML::Entities + - HTML::HeadParser + - LWP + - Crypt::SSLeay? (ssl?) + - IO::Zlib? (zlib?) + - IMAP? + - Net::Telnet? + - Archive::Zip? + - Mail::Send? + - Date::Calc? + - XML? XML::Simple? (expat?) (there is builtin xml support) + - RSS? + - DBI + - DBD::SQLite? (sqlite?) + - SOAP? XML-RPC? + +=head1 FUTURE POSSIBILITIES + +- Remote console (Bluetooth/IR) +- S60 GUI support +- S60 PDA support +- Phone APIs +- S80 +- UIQ diff --git a/symbian/bld.inf b/symbian/bld.inf new file mode 100644 index 0000000000..c4489677f0 --- /dev/null +++ b/symbian/bld.inf @@ -0,0 +1,4 @@ +PRJ_MMPFILES +PerlApp.mmp +PerlRecog.mmp + diff --git a/symbian/config.pl b/symbian/config.pl new file mode 100644 index 0000000000..e2cd2c682a --- /dev/null +++ b/symbian/config.pl @@ -0,0 +1,768 @@ +#!/usr/bin/perl -w + +# Copyright (c) 2004-2005 Nokia. All rights reserved. + +use strict; +use lib "symbian"; + +print "Configuring...\n"; +print "Configuring with: Perl version $] ($^X)\n"; + +do "sanity.pl"; + +my %VERSION = %{ do "version.pl" }; + +printf "Configuring for: Perl version $VERSION{REVISION}.%03d%03d\n", + $VERSION{VERSION}, $VERSION{SUBVERSION}; + +my $VERSION = "$VERSION{REVISION}$VERSION{VERSION}$VERSION{SUBVERSION}"; +my $R_V_SV = "$VERSION{REVISION}.$VERSION{VERSION}.$VERSION{SUBVERSION}"; + +my $SDK = do "sdk.pl"; +my %PORT = %{ do "port.pl" }; + +my ( $SYMBIAN_VERSION, $SDK_VERSION ) = ( $SDK =~ m!\\Symbian\\(.+?)\\(.+)$! ); + +if ($SDK eq 'C:\Symbian\Series60_1_2_CW') { + ( $SYMBIAN_VERSION, $SDK_VERSION ) = qw(6.1 1.2); +} + +my $WIN = $ENV{WIN} ; # 'wins', 'winscw' (from sdk.pl) +my $ARM = 'thumb'; # 'thumb', 'armi' +my $S60SDK = $ENV{S60SDK}; # qw(1.2 2.0 2.1 2.6) (from sdk.pl) + +my $UREL = $ENV{UREL}; # from sdk.pl +$UREL =~ s/-ARM-/$ARM/; +my $UARM = $ENV{UARM}; # from sdk.pl + +die "$0: SDK not recognized\n" + if !defined($SYMBIAN_VERSION) || !defined($SDK_VERSION) || !defined($S60SDK); + +die "$0: does not know which Windows compiler to use\n" + unless defined $WIN; + +print "Symbian $SYMBIAN_VERSION SDK $S60SDK ($WIN) installed at $SDK\n"; + +my $CWD = do "cwd.pl"; +print "Build directory $CWD\n"; + +die "$0: '+' in cwd does not work with SDK 1.2\n" + if $S60SDK eq '1.2' && $CWD =~ /\+/; + +my @unclean; +my @mmp; + +sub create_mmp { + my ( $target, $type, @x ) = @_; + my $miniperl = $target eq 'miniperl'; + my $perl = $target eq 'perl'; + my $mmp = "$target.mmp"; + my $targetpath = $miniperl + || $perl ? "TARGETPATH\t\\System\\Apps\\Perl" : ""; + if ( open( my $fh, ">$mmp" ) ) { + print "\t$mmp\n"; + push @mmp, $mmp; + push @unclean, $mmp; + print $fh <<__EOF__; +TARGET $target.$type +TARGETTYPE $type +$targetpath +EPOCHEAPSIZE 1024 8388608 +EPOCSTACKSIZE 65536 +EXPORTUNFROZEN +SRCDBG +__EOF__ + print $fh "MACRO\t__SERIES60_1X__\n" if $S60SDK =~ /^1\./; + print $fh "MACRO\t__SERIES60_2X__\n" if $S60SDK =~ /^2\./; + my ( @c, %c ); + @c = map { glob } qw(*.c); # Find the .c files. + @c = map { lc } @c; # Lowercase the names. + @c = grep { !/malloc\.c/ } @c; # Use the system malloc. + @c = grep { !/main\.c/ } @c; # main.c must be explicit. + push @c, map { lc } @x; + @c = map { s:^\.\./::; $_ } @c; # Remove the leading ../ + @c = map { $c{$_}++ } @c; # Uniquefy. + @c = sort keys %c; # Beautify. + + for (@c) { + print $fh "SOURCE\t\t$_\n"; + } + print $fh <<__EOF__; +SOURCEPATH $CWD +USERINCLUDE $CWD +USERINCLUDE $CWD\\ext\\DynaLoader +USERINCLUDE $CWD\\symbian +SYSTEMINCLUDE \\epoc32\\include\\libc +SYSTEMINCLUDE \\epoc32\\include +LIBRARY euser.lib +LIBRARY estlib.lib +__EOF__ + if ( $miniperl || $perl || $type eq 'dll' ) { + print $fh <<__EOF__; +LIBRARY charconv.lib +LIBRARY commonengine.lib +LIBRARY hal.lib +LIBRARY estor.lib +__EOF__ + } + if ( $type eq 'exe' ) { + print $fh <<__EOF__; +STATICLIBRARY ecrt0.lib +__EOF__ + } + if ($miniperl) { + print $fh <<__EOF__; +MACRO PERL_MINIPERL +__EOF__ + } + if ($perl) { + print $fh <<__EOF__; +MACRO PERL_PERL +__EOF__ + } + print $fh <<__EOF__; +MACRO PERL_CORE +MACRO MULTIPLICITY +MACRO PERL_IMPLICIT_CONTEXT +__EOF__ + unless ( $miniperl || $perl ) { + print $fh <<__EOF__; +MACRO PERL_GLOBAL_STRUCT +MACRO PERL_GLOBAL_STRUCT_PRIVATE +__EOF__ + } + close $fh; + } + else { + warn "$0: failed to open $mmp for writing: $!\n"; + } +} + +sub create_bld_inf { + if ( open( BLD_INF, ">bld.inf" ) ) { + print "\tbld.inf\n"; + push @unclean, "bld.inf"; + print BLD_INF <<__EOF__; +PRJ_PLATFORMS +${WIN} ${ARM} +PRJ_MMPFILES +__EOF__ + for (@mmp) { print BLD_INF $_, "\n" } + close BLD_INF; + } + else { + warn "$0: failed to open bld.inf for writing: $!\n"; + } +} + +my %config; + +sub load_config_sh { + if ( open( CONFIG_SH, "symbian/config.sh" ) ) { + while (<CONFIG_SH>) { + if (/^(\w+)=['"]?(.*?)["']?$/) { + my ( $var, $val ) = ( $1, $2 ); + $val =~ s/x.y.z/$R_V_SV/gi; + $val =~ s/thumb/$ARM/gi; + $val = "'$SYMBIAN_VERSION'" if $var eq 'osvers'; + $val = "'$SDK_VERSION'" if $var eq 'sdkvers'; + $config{$var} = $val; + } + } + close CONFIG_SH; + } + else { + warn "$0: failed to open symbian\\config.sh for reading: $!\n"; + } +} + +sub create_config_h { + load_config_sh(); + if ( open( CONFIG_H, ">config.h" ) ) { + print "\tconfig.h\n"; + push @unclean, "config.h"; + if ( open( CONFIG_H_SH, "config_h.SH" ) ) { + while (<CONFIG_H_SH>) { + last if /\#ifndef _config_h_/; + } + print CONFIG_H <<__EOF__; +/* + * Package name : perl + * Source directory : . + * Configuration time: + * Configured by : + * Target system : symbian + */ + +#ifndef _config_h_ +__EOF__ + while (<CONFIG_H_SH>) { + last if /!GROK!THIS/; + s/\$(\w+)/exists $config{$1} ? $config{$1} : ""/eg; + s/^#undef\s+(\S+).+/#undef $1/g; + s:\Q/**/::; + print CONFIG_H; + } + close CONFIG_H_SH; + } + else { + warn "$0: failed to open ../config_h.SH for reading: $!\n"; + } + close CONFIG_H; + } + else { + warn "$0: failed to open config.h for writing: $!\n"; + } +} + +sub create_DynaLoader_cpp { + print "\text\\DynaLoader\\DynaLoader.cpp\n"; + system( +q[perl -Ilib lib\ExtUtils\xsubpp ext\DynaLoader\dl_symbian.xs >ext\DynaLoader\DynaLoader.cpp] + ) == 0 + or die "$0: creating DynaLoader.cpp failed: $!\n"; + push @unclean, 'ext\DynaLoader\DynaLoader.cpp'; + +} + +sub create_symbian_port_h { + print "\tsymbian\\symbian_port.h\n"; + if ( open( SYMBIAN_PORT_H, ">symbian/symbian_port.h" ) ) { + $S60SDK =~ /^(\d+)\.(\d+)$/; + my ($sdkmajor, $sdkminor) = ($1, $2); + print SYMBIAN_PORT_H <<__EOF__; +/* Copyright (c) 2004-2005, Nokia. All rights reserved. */ + +#ifndef __symbian_port_h__ +#define __symbian_port_h__ + +#define PERL_SYMBIANPORT_MAJOR $PORT{dll}->{MAJOR} +#define PERL_SYMBIANPORT_MINOR $PORT{dll}->{MINOR} +#define PERL_SYMBIANPORT_PATCH $PORT{dll}->{PATCH} + +#define PERL_SYMBIANSDK_FLAVOR L"Series 60" +#define PERL_SYMBIANSDK_MAJOR $sdkmajor +#define PERL_SYMBIANSDK_MINOR $sdkminor + +#endif /* #ifndef __symbian_port_h__ */ +__EOF__ + close(SYMBIAN_PORT_H); + push @unclean, 'symbian\symbian_port.h'; + } + else { + warn "$0: failed to open symbian/symbian_port.h for writing: $!\n"; + } +} + +sub create_perlmain_c { + print "\tperlmain.c\n"; + system( +q[perl -ne "print qq[ char *file = __FILE__;\n] if /dXSUB_SYS/;print;print qq[ newXS(\"DynaLoader::boot_DynaLoader\", boot_DynaLoader, file);\n] if /dXSUB_SYS/;print qq[EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);\n] if /Do not delete this line/" miniperlmain.c > perlmain.c] + ) == 0 + or die "$0: Creating perlmain.c failed: $!\n"; + push @unclean, 'perlmain.c'; +} + +sub create_PerlApp_pkg { + print "\tsymbian\\PerlApp.pkg\n"; + if ( open( PERLAPP_PKG, ">symbian\\PerlApp.pkg" ) ) { + my $APPS = $UREL; + if ($S60SDK ne '1.2' || $SDK =~ m/_CW$/) { # Do only if not in 1.2 VC. + $APPS =~ s!\\epoc32\\release\\(.+)\\$UARM$!\\epoc32\\data\\z\\system\\apps\\PerlApp!i; + } + print PERLAPP_PKG <<__EOF__; +; !!!!!! DO NOT EDIT THIS FILE !!!!!! +; This file is built by symbian\\config.pl. +; Any changes made here will be lost! +; +; PerlApp.pkg +; +; Note that the demo_pl needs to be run to create the demo .pl scripts. +; +; Languages +&EN; + +; Standard SIS file header +#{"PerlApp"},(0x102015F6),0,1,0 + +; Supports Series 60 v0.9 +(0x101F6F88), 0, 0, 0, {"Series60ProductID"} + +; Files +"$UREL\\PerlApp.APP"-"!:\\system\\apps\\PerlApp\\PerlApp.app" +"$UREL\\PerlRecog.mdl"-"!:\\system\\recogs\\PerlRecog.mdl" +"$APPS\\PerlApp.rsc"-"!:\\system\\apps\\PerlApp\\PerlApp.rsc" +"$APPS\\PerlApp.aif"-"!:\\system\\apps\\PerlApp\\PerlApp.aif" +__EOF__ + if ( open( DEMOS, "perl symbian\\demo_pl list |" ) ) { + while (<DEMOS>) { + chomp; + print PERLAPP_PKG qq["$_"-"!:\\Perl\\$_"\n]; + } + close(DEMOS); + } + close(PERLAPP_PKG); + } + else { + die "$0: symbian\\PerlApp.pkg: $!\n"; + } + push @unclean, 'symbian\PerlApp.pkg'; +} + +print "Creating...\n"; +create_mmp( + 'miniperl', 'exe', + 'miniperlmain.c', 'symbian\symbian_stubs.c', + 'symbian\PerlBase.cpp', 'symbian\symbian_utils.cpp', +); +create_mmp( + "perl", 'exe', + 'perlmain.c', 'symbian\symbian_stubs.c', + 'symbian\symbian_utils.cpp', 'symbian\PerlBase.cpp', + 'ext\DynaLoader\DynaLoader.cpp', +); + +create_mmp( + "perl$VERSION", 'dll', + 'symbian\symbian_dll.cpp', 'symbian\symbian_stubs.c', + 'symbian\symbian_utils.cpp', 'symbian\PerlBase.cpp', + 'ext\DynaLoader\DynaLoader.cpp', +); + +create_bld_inf(); +create_config_h(); +create_perlmain_c(); +create_symbian_port_h(); +create_DynaLoader_cpp(); +create_PerlApp_pkg(); + +if ( open( PERLAPP_MMP, ">symbian/PerlApp.mmp" ) ) { + my @MACRO; + push @MACRO, '__SERIES60_1X__' if $S60SDK =~ /^1\./; + push @MACRO, '__SERIES60_2X__' if $S60SDK =~ /^2\./; + print PERLAPP_MMP <<__EOF__; +// !!!!!! DO NOT EDIT THIS FILE !!!!!! +// This file is built by symbian\\config.pl. +// Any changes made here will be lost! +TARGET PerlApp.app +TARGETTYPE app +UID 0x100039CE 0x102015F6 +TARGETPATH \\system\\apps\\PerlApp +SRCDBG +EXPORTUNFROZEN +SOURCEPATH . +SOURCE PerlApp.cpp + +RESOURCE PerlApp.rss + +USERINCLUDE . +USERINCLUDE .. +USERINCLUDE \\symbian\\perl\\$R_V_SV\\include + +SYSTEMINCLUDE \\epoc32\\include +SYSTEMINCLUDE \\epoc32\\include\\libc + +LIBRARY apparc.lib +LIBRARY avkon.lib +LIBRARY bafl.lib +LIBRARY charconv.lib +LIBRARY commondialogs.lib +LIBRARY cone.lib +LIBRARY efsrv.lib +LIBRARY eikcore.lib +LIBRARY estlib.lib +LIBRARY euser.lib +LIBRARY perl$VERSION.lib + +AIF PerlApp.aif . PerlAppAif.rss +__EOF__ + if (@MACRO) { + for my $macro (@MACRO) { + print PERLAPP_MMP <<__EOF__; +MACRO $macro +__EOF__ + } + } + close(PERLAPP_MMP); + push @unclean, 'symbian\PerlApp.mmp'; +} +else { + warn "$0: failed to create symbian\\PerlApp.mmp"; +} + +if ( open( MAKEFILE, ">Makefile" ) ) { + my $perl = "perl$VERSION"; + my $windef1 = "$SDK\\Epoc32\\Build$CWD\\$perl\\$WIN\\$perl.def"; + my $windef2 = "..\\BWINS\\${perl}u.def"; + my $armdef1 = "$SDK\\Epoc32\\Build$CWD\\$perl\\$ARM\\$perl.def"; + my $armdef2 = "..\\BMARM\\${perl}u.def"; + print "\tMakefile\n"; + print MAKEFILE <<__EOF__; +help: + \@echo === Perl for Symbian === + \@echo Useful targets: + \@echo all win arm clean + \@echo perldll.sis perlext.sis perlsdk.zip + +WIN = ${WIN} +ARM = ${ARM} + +all: build + +build: rename_makedef build_win build_arm + +@unclean: symbian\\config.pl + perl symbian\\config.pl + +build_win: abld.bat win_perl.mf win_miniperl.mf win_${VERSION}.mf perldll_win + +build_vc6: abld.bat win_perl.mf win_miniperl.mf win_${VERSION}.mf vc6.mf perldll_win + +build_arm: abld.bat perl_arm miniperl_arm arm_${VERSION}.mf perldll_arm + +miniperl_win: miniperl.mmp abld.bat win_miniperl.mf rename_makedef + abld build \$(WIN) udeb miniperl + +miniperl_arm: miniperl.mmp abld.bat arm_miniperl.mf rename_makedef + abld build \$(ARM) $UARM miniperl + +miniperl: miniperl_win miniperl_arm + +perl: perl_win perl_arm + +perl_win: perl.mmp abld.bat win_perl.mf rename_makedef + abld build \$(WIN) perl + +perl_arm: perl.mmp abld.bat arm_perl.mf rename_makedef + abld build \$(ARM) $UARM perl + +perldll_win: perl${VERSION}_win freeze_win perl${VERSION}_win + +perl${VERSION}_win: perl$VERSION.mmp abld.bat rename_makedef + abld build \$(WIN) perl$VERSION + +perldll_arm: perl${VERSION}_arm freeze_arm perl${VERSION}_arm + +perl${VERSION}_arm: perl$VERSION.mmp arm_${VERSION}.mf abld.bat rename_makedef + abld build \$(ARM) $UARM perl$VERSION + +perldll perl$VERSION: perldll_win perldll_arm + +win: miniperl_win perl_win perldll_win + +arm: miniperl_arm perl_arm perldll_arm + +rename_makedef: + -ren makedef.pl nomakedef.pl + +# Symbian SDK has a makedef.pl of its own, +# and we don't need Perl's. +rerename_makedef: + -ren nomakedef.pl makedef.pl + +abld.bat abld: bld.inf + bldmake bldfiles + +makefiles: win.mf arm.mf vc6.mf + +vc6: win.mf vc6.mf build_vc6 + +win_miniperl.mf: abld.bat symbian\\config.pl + abld makefile \$(WIN) miniperl + echo > win_miniperl.mf + +win_perl.mf: abld.bat symbian\\config.pl + abld makefile \$(WIN) perl + echo > win_perl.mf + +win_${VERSION}.mf: abld.bat symbian\\config.pl + abld makefile \$(WIN) perl${VERSION} + echo > win_${VERSION}.mf + +symbian\\win.mf: + cd symbian; make win.mf + +win.mf: win_miniperl.mf win_perl.mf win_${VERSION}.mf symbian\\win.mf + +arm_miniperl.mf: abld.bat symbian\\config.pl + abld makefile \$(ARM) miniperl + echo > arm_miniperl.mf + +arm_perl.mf: abld.bat symbian\\config.pl + abld makefile \$(ARM) perl + echo > arm_perl.mf + +arm_${VERSION}.mf: abld.bat symbian\\config.pl + abld makefile \$(ARM) perl${VERSION} + echo > arm_${VERSION}.mf + +arm.mf: arm_miniperl.mf arm_perl.mf arm_${VERSION}.mf + +vc6.mf: abld.bat symbian\\config.pl + abld makefile vc6 + echo > vc6.mf + +PM = lib\\Config.pm lib\\Cross.pm lib\\lib.pm ext\\DynaLoader\\DynaLoader.pm ext\\DynaLoader\\XSLoader.pm ext\\Errno\\Errno.pm +POD = lib\\Config.pod + +pm: \$(PM) + +XLIB = -Ixlib\\symbian + +XSBOPT = --win=\$(WIN) --arm=\$(ARM) + +lib\\Config.pm: + copy symbian\\config.sh config.sh + perl -pi.bak -e "s:x\\.y\\.z+:$R_V_SV:g" config.sh + perl \$(XLIB) configpm --cross=symbian + copy xlib\\symbian\\Config.pm lib\\Config.pm + perl -pi.bak -e "s:x\\.y\\.z:$R_V_SV:g" lib\\Config.pm + perl -pi.bak -e "s:5\\.\\d+\\.\\d+:$R_V_SV:g" lib\\Config.pm + -perl -pi.bak -e "s:x\\.y\\.z:$R_V_SV:g" xlib\\symbian\\Config_heavy.pl + +lib\\lib.pm: + perl lib\\lib_pm.PL + +ext\\DynaLoader\\DynaLoader.pm: + -del /f ext\\DynaLoader\\DynaLoader.pm + perl -Ixlib\\symbian ext\\DynaLoader\\DynaLoader_pm.PL + perl -pi.bak -e "s/__END__//" DynaLoader.pm + copy /y DynaLoader.pm ext\\DynaLoader\\DynaLoader.pm + -del /f DynaLoader.pm DynaLoader.pm.bak + +ext\\DynaLoader\\XSLoader.pm: + perl \$(XLIB) symbian\\xsbuild.pl \$(XSBOPT) XSLoader + +ext\\Errno\\Errno.pm: + perl \$(XLIB) symbian\\xsbuild.pl \$(XSBOPT) Errno + +miniperlexe.sis: miniperl_arm symbian\\makesis.pl + perl \$(XLIB) symbian\\makesis.pl miniperl + +perlexe.sis: perl_arm symbian\\makesis.pl + perl \$(XLIB) symbian\\makesis.pl perl + + +allsis: all miniperlexe.sis perlexe.sis perldll.sis perllib.sis perlext.sis perlapp.sis + +perldll.sis perl$VERSION.sis: perldll_arm pm symbian\\makesis.pl + perl \$(XLIB) symbian\\makesis.pl perl${VERSION}dll + +perllib.sis: \$(PM) + perl \$(XLIB) symbian\\makesis.pl perl${VERSION}lib + +perlext.sis: perldll_arm buildext_sis + perl symbian\\makesis.pl perl${VERSION}ext + +EXT = Cwd Data::Dumper Devel::Peek Digest::MD5 Errno Fcntl File::Glob Filter::Util::Call IO List::Util MIME::Base64 PerlIO::scalar PerlIO::via SDBM_File Socket Storable Time::HiRes XSLoader attrs + +buildext: perldll symbian\\xsbuild.pl + perl \$(XLIB) symbian\\xsbuild.pl \$(XSBOPT) \$(EXT) + +buildext_sis: perldll.sis symbian\\xsbuild.pl + perl \$(XLIB) symbian\\xsbuild.pl \$(XSBOPT) --sis \$(EXT) + +cleanext: symbian\\xsbuild.pl + perl \$(XLIB) symbian\\xsbuild.pl \$(XSBOPT) --clean \$(EXT) + +distcleanext: symbian\\xsbuild.pl + perl \$(XLIB) symbian\\xsbuild.pl \$(XSBOPT) --distclean \$(EXT) + +sis makesis: miniperl perl perldll pm buildext perlapp.sis + perl \$(XLIB) symbian\\makesis.pl + +APIDIR = \\Symbian\\perl\\$R_V_SV + +sdkinstall: + -mkdir \\Symbian\\perl + -mkdir \\Symbian\\perl\\$R_V_SV + -mkdir \$(APIDIR)\\include + -mkdir \$(APIDIR)\\include\\symbian + -mkdir \$(APIDIR)\\lib + -mkdir \$(APIDIR)\\lib\\ExtUtils + -mkdir \$(APIDIR)\\pod + -mkdir \$(APIDIR)\\bin + -mkdir \$(BINDIR) + copy /y *.h \$(APIDIR)\\include + - copy /y *.inc \$(APIDIR)\\include + copy /y lib\\ExtUtils\\xsubpp \$(APIDIR)\\lib\\ExtUtils + copy /y lib\\ExtUtils\\typemap \$(APIDIR)\\lib\\ExtUtils + copy /y symbian\\xsbuild.pl \$(APIDIR)\\bin + copy /y symbian\\PerlBase.h \$(APIDIR)\\include + copy /y symbian\\symbian*.h \$(APIDIR)\\include\\symbian + copy /y symbian\\PerlBase.pod \$(APIDIR)\\pod + +RELDIR = $SDK\\epoc32\\release +RELWIN = \$(RELDIR)\\\$(WIN)\\udeb +RELARM = \$(RELDIR)\\\$(ARM)\\$UARM + +perlsdk.zip: perldll sdkinstall + zip -r perl${VERSION}sdk.zip \$(RELWIN)\\perl$VERSION.* \$(RELARM)\\perl$VERSION.* \$(APIDIR) + \@echo perl${VERSION}sdk.zip created. + +perlapp: sdkinstall perlapp_win perlapp_arm + +perlapp_win: config.h + cd symbian; make perlapp_win + +perlapp_arm: config.h + cd symbian; make perlapp_arm + +perlapp_demo_extract: + cd symbian; make perlapp_demo_extract + +perlapp.sis: perlapp_arm + cd symbian; make perlapp.sis + +perlapp.zip: + cd symbian; zip perlapp.zip PerlApp.* PerlRecog.* PerlBase.* demo_pl + +zip: perlsdk.zip perlapp.zip + +freeze: freeze_win freeze_arm + +freeze_win: + abld freeze \$(WIN) perl$VERSION + +freeze_arm: + abld freeze \$(ARM) perl$VERSION + +defrost: defrost_win defrost_arm + +defrost_win: + -del /f $windef1 + -del /f $windef2 + +defrost_arm: + -del /f $armdef1 + -del /f $armdef2 + +clean_win: abld.bat + abld clean \$(WIN) + +clean_arm: abld.bat + abld clean \$(ARM) + +clean: clean_win clean_arm rerename_makedef + -del /f \$(PM) + -del /f \$(POD) + -del /f lib\\Config.pm.bak + -del /f xlib\\symbian\\Config_heavy.pl + -rmdir /s /q xlib + -del /f config.sh + -del /f DynaLoader.pm ext\\DynaLoader\\DynaLoader.pm + -del /f ext\\DynaLoader\\Makefile + -del /f ext\\SDBM_File\\sdbm\\Makefile + -del /f symbian\\*.lst + -del /f abld.bat @unclean *.pkg *.sis *.zip + -del /f symbian\\abld.bat symbian\\*.sis symbian\\*.zip + -del /f symbian\\perl5*.pkg symbian\\miniperl.pkg + -del arm_*.mf win_*.mf vc6*.mf + -perl symbian\\xsbuild.pl \$(XSBOPT) --clean \$(EXT) + -rmdir /s /q perl${VERSION}_Data + -cd symbian; make clean + +reallyclean: abld.bat + abld reallyclean + +distclean: defrost reallyclean clean + -perl symbian\\xsbuild.pl \$(XSBOPT) --distclean \$(EXT) + -del /f config.h config.sh.bak symbian\\symbian_port.h + -del /f Makefile symbian\\PerlApp.mmp + -del /f BMARM\\*.def + -del /f *.cwlink *.resources *.pref + -del /f perl${VERSION}.xml perl${VERSION}.mcp uid.cpp + -rmdir /s /q BMARM + cd symbian; make distclean + -del /f symbian\\Makefile +__EOF__ + close MAKEFILE; +} +else { + warn "$0: failed to create Makefile: $!\n"; +} + +if ( open( MAKEFILE, ">symbian/Makefile")) { + my $wrap = $S60SDK eq '1.2' && $SDK !~ /_CW$/; + my $ABLD = $wrap ? 'perl b.pl': 'abld'; + print "\tsymbian/Makefile\n"; + print MAKEFILE <<__EOF__; +WIN = $WIN +ARM = $ARM +ABLD = $ABLD + +abld.bat: + bldmake bldfiles + +perlapp_win: abld.bat ..\\config.h PerlApp.h PerlApp.cpp + bldmake bldfiles + \$(ABLD) build \$(WIN) udeb + +perlapp_arm: ..\\config.h PerlApp.h PerlApp.cpp + bldmake bldfiles + \$(ABLD) build \$(ARM) $UARM + +win.mf: + bldmake bldfiles + abld makefile vc6 + +perlapp_demo_extract: + perl demo_pl extract + +perlapp.sis: perlapp_arm perlapp_demo_extract + -del /f perlapp.SIS + makesis perlapp.pkg + copy /y perlapp.SIS ..\\perlapp.SIS + +clean: + -perl demo_pl cleanup + -del /f perlapp.sis + -del /f b.pl + +distclean: clean + -del /f *.cwlink *.resources *.pref + -del /f PerlApp.xml PerlApp.mcp uid.cpp + -rmdir /s /q PerlApp_Data + -del /f abld.bat +__EOF__ + close(MAKEFILE); + if ($wrap) { + if ( open( B_PL, ">symbian/b.pl")) { + print B_PL <<'__EOF__'; +# abld.pl wrapper. + +# nmake doesn't like MFLAGS and MAKEFLAGS being set to -w and w. +delete $ENV{MFLAGS}; +delete $ENV{MAKEFLAGS}; + +system("abld @ARGV"); +__EOF__ + close(B_PL); + } else { + warn "$0: failed to create symbian/b.pl: $!\n"; + } + } +} else { + warn "$0: failed to create symbian/Makefile: $!\n"; +} + +print "Deleting...\n"; +for my $config ( + # Do not delete config.h here. + "config.sh", + "lib\\Config.pm", + "xlib\\symbian\\Config.pm", + "xlib\\symbian\\Config_heavy.pl", + ) { + print "\t$config\n"; + unlink($config); +} + +print <<__EOM__; +Configuring done. +Now you can run: + make all + make allsis +__EOM__ + +1; # Happy End. diff --git a/symbian/config.sh b/symbian/config.sh new file mode 100644 index 0000000000..1c1fa01b99 --- /dev/null +++ b/symbian/config.sh @@ -0,0 +1,768 @@ +#!\\bin\\sh +PERL_CONFIG_SH='true' +_a='.a' +_o='.o' +afs='false' +afsroot='/afs' +alignbytes='4' +apiversion='5.005' +ar=':' +archlib='\\system\\libs\\perl\\x.y.z\\thumb-symbian' +archlibexp='\\system\\libs\\perl\\x.y.z\\thumb-symbian' +archname='thumb-symbian' +asctime_r_proto='0' +bin='\\system\\apps\\perl' +binexp='\\system\\apps\\perl' +bincompat5005='n' +byteorder='1234' +castflags='0' +cc='gcc' +cccdlflags='' +ccdlflags='' +charsize='1' +clocktype='clock_t' +cpp_stuff='42' +cppminus='-' +cpprun='gcc -E' +cppstdin='gcc -E' +crypt_r_proto='0' +ctermid_r_proto='0' +ctime_r_proto='0' +d_Gconvert='sprintf((b),"%.*g",(n),(x))' +d_PRIEUldbl='undef' +d_PRIFUldbl='undef' +d_PRIGUldbl='undef' +d_PRIXU64='undef' +d_PRId64='undef' +d_PRIeldbl='undef' +d_PRIfldbl='undef' +d_PRIgldbl='undef' +d_PRIi64='undef' +d_PRIo64='undef' +d_PRIu64='undef' +d_PRIx64='undef' +d_SCNfldbl='undef' +d__fwalk='undef' +d_access='undef' +d_accessx='undef' +d_aintl='undef' +d_alarm='undef' +d_archlib='define' +d_asctime_r='undef' +d_atolf='undef' +d_atoll='undef' +d_attribut='undef' +d_bcmp='undef' +d_bcopy='undef' +d_bsd='undef' +d_bsdgetpgrp='undef' +d_bsdsetpgrp='undef' +d_bzero='undef' +d_casti32='undef' +d_castneg='undef' +d_charvspr='undef' +d_chown='undef' +d_chroot='undef' +d_chsize='undef' +d_class='undef' +d_closedir='undef' +d_cmsghdr_s='undef' +d_const='define' +d_copysignl='undef' +d_crypt='undef' +d_crypt_r='undef' +d_csh='undef' +d_ctermid_r='undef' +d_ctime_r='undef' +d_cuserid='undef' +d_dbl_dig='undef' +d_dbminitproto='undef' +d_difftime='undef' +d_dirfd='undef' +d_dirnamlen='define' +d_dlerror='undef' +d_dlopen='undef' +d_dlsymun='undef' +d_dosuid='undef' +d_drand48_r='undef' +d_drand48proto='undef' +d_dup2='undef' +d_eaccess='undef' +d_endgrent='undef' +d_endgrent_r='undef' +d_endhent='undef' +d_endhostent_r='undef' +d_endnent='undef' +d_endnetent_r='undef' +d_endpent='undef' +d_endprotoent_r='undef' +d_endpwent='undef' +d_endpwent_r='undef' +d_endsent='undef' +d_endservent_r='undef' +d_eofnblk='undef' +d_eunice='undef' +d_faststdio='undef' +d_fchdir='undef' +d_fchmod='undef' +d_fchown='undef' +d_fcntl='undef' +d_fcntl_can_lock='undef' +d_fd_macros='undef' +d_fd_set='undef' +d_fds_bits='undef' +d_fgetpos='undef' +d_finite='undef' +d_finitel='undef' +d_flexfnam='undef' +d_flock='undef' +d_flockproto='undef' +d_fork='undef' +d_fp_class='undef' +d_fpathconf='undef' +d_fpclass='undef' +d_fpclassify='undef' +d_fpclassl='undef' +d_fpos64_t='undef' +d_frexpl='undef' +d_fs_data_s='undef' +d_fseeko='undef' +d_fsetpos='define' +d_fstatfs='undef' +d_fstatvfs='undef' +d_fsync='undef' +d_ftello='undef' +d_ftime='undef' +d_getcwd='define' +d_getespwnam='undef' +d_getfsstat='undef' +d_getgrent='undef' +d_getgrent_r='undef' +d_getgrgid_r='undef' +d_getgrnam_r='undef' +d_getgrps='undef' +d_gethbyaddr='define' +d_gethbyname='define' +d_gethent='undef' +d_gethname='define' +d_gethostbyaddr_r='undef' +d_gethostbyname_r='undef' +d_gethostent_r='undef' +d_gethostprotos='define' +d_getitimer='undef' +d_getlogin='undef' +d_getlogin_r='undef' +d_getmnt='undef' +d_getmntent='undef' +d_getnbyaddr='undef' +d_getnbyname='undef' +d_getnent='undef' +d_getnetbyaddr_r='undef' +d_getnetbyname_r='undef' +d_getnetent_r='undef' +d_getnetprotos='undef' +d_getpagsz='undef' +d_getpbyname='define' +d_getpbynumber='define' +d_getpent='undef' +d_getpgid='undef' +d_getpgrp2='undef' +d_getpgrp='undef' +d_getppid='undef' +d_getprior='undef' +d_getprotobyname_r='undef' +d_getprotobynumber_r='undef' +d_getprotoent_r='undef' +d_getprotoprotos='define' +d_getprpwnam='undef' +d_getpwent='undef' +d_getpwent_r='undef' +d_getpwnam_r='undef' +d_getpwuid_r='undef' +d_getsbyname='define' +d_getsbyport='define' +d_getsent='undef' +d_getservbyname_r='undef' +d_getservbyport_r='undef' +d_getservent_r='undef' +d_getservprotos='define' +d_getspent='undef' +d_getspnam='undef' +d_getspnam_r='undef' +d_gettimeod='define' +d_gmtime_r='undef' +d_gnulibc='undef' +d_grpasswd='undef' +d_hasmntopt='undef' +d_htonl='define' +d_ilogbl='undef' +d_index='undef' +d_inetaton='undef' +d_int64_t='undef' +d_isascii='undef' +d_isfinite='undef' +d_isinf='undef' +d_isnan='undef' +d_isnanl='undef' +d_killpg='undef' +d_lchown='undef' +d_ldbl_dig='undef' +d_libm_lib_version='undef' +d_link='undef' +d_localtime_r='undef' +d_locconv='undef' +d_lockf='undef' +d_longdbl='undef' +d_longlong='undef' +d_lseekproto='undef' +d_lstat='undef' +d_madvise='undef' +d_mblen='undef' +d_mbstowcs='undef' +d_mbtowc='undef' +d_memchr='define' +d_memcmp='define' +d_memcpy='define' +d_memmove='define' +d_memset='define' +d_mkdir='define' +d_mkdtemp='undef' +d_mkfifo='undef' +d_mkstemp='undef' +d_mkstemps='undef' +d_mktime='undef' +d_mmap='undef' +d_modfl='undef' +d_modfl_pow32_bug='undef' +d_modflproto='undef' +d_mprotect='undef' +d_msg='undef' +d_msg_ctrunc='undef' +d_msg_dontroute='undef' +d_msg_oob='undef' +d_msg_peek='undef' +d_msg_proxy='undef' +d_msgctl='undef' +d_msgget='undef' +d_msghdr_s='undef' +d_msgrcv='undef' +d_msgsnd='undef' +d_msync='undef' +d_munmap='undef' +d_mymalloc='undef' +d_nice='undef' +d_nl_langinfo='undef' +d_nv_preserves_uv='undef' +d_off64_t='undef' +d_old_pthread_create_joinable='undef' +d_oldpthreads='undef' +d_oldsock='undef' +d_open3='undef' +d_pathconf='undef' +d_pause='undef' +d_perl_otherlibdirs='undef' +d_phostname='undef' +d_pipe='undef' +d_poll='undef' +d_portable='undef' +d_procselfexe='undef' +d_pthread_atfork='undef' +d_pthread_attr_setscope='undef' +d_pthread_yield='undef' +d_pwage='undef' +d_pwchange='undef' +d_pwclass='undef' +d_pwcomment='undef' +d_pwexpire='undef' +d_pwgecos='undef' +d_pwpasswd='undef' +d_pwquota='undef' +d_qgcvt='undef' +d_quad='undef' +d_random_r='undef' +d_readdir64_r='undef' +d_readdir='define' +d_readdir_r='undef' +d_readlink='undef' +d_readv='undef' +d_recvmsg='undef' +d_rename='define' +d_rewinddir='define' +d_rmdir='define' +d_safebcpy='undef' +d_safemcpy='undef' +d_sanemcmp='undef' +d_sbrkproto='undef' +d_scalbnl='undef' +d_sched_yield='undef' +d_scm_rights='undef' +d_seekdir='define' +d_select='undef' +d_sem='undef' +d_semctl='undef' +d_semctl_semid_ds='undef' +d_semctl_semun='undef' +d_semget='undef' +d_semop='undef' +d_sendmsg='undef' +d_setegid='undef' +d_seteuid='undef' +d_setgrent='undef' +d_setgrent_r='undef' +d_setgrps='undef' +d_sethent='undef' +d_sethostent_r='undef' +d_setitimer='undef' +d_setlinebuf='undef' +d_setlocale='undef' +d_setlocale_r='undef' +d_setnent='undef' +d_setnetent_r='undef' +d_setpent='undef' +d_setpgid='undef' +d_setpgrp2='undef' +d_setpgrp='undef' +d_setprior='undef' +d_setproctitle='undef' +d_setprotoent_r='undef' +d_setpwent='undef' +d_setpwent_r='undef' +d_setregid='undef' +d_setresgid='undef' +d_setresuid='undef' +d_setreuid='undef' +d_setrgid='undef' +d_setruid='undef' +d_setsent='undef' +d_setservent_r='undef' +d_setsid='undef' +d_setvbuf='define' +d_sfio='undef' +d_shm='undef' +d_shmat='undef' +d_shmatprototype='undef' +d_shmctl='undef' +d_shmdt='undef' +d_shmget='undef' +d_sigaction='undef' +d_sigprocmask='undef' +d_sigsetjmp='undef' +d_sitecustomize='undef' +d_sockatmark='undef' +d_sockatmarkproto='undef' +d_socket='define' +d_socklen_t='undef' +d_sockpair='undef' +d_socks5_init='undef' +d_sqrtl='undef' +d_srand48_r='undef' +d_srandom_r='undef' +d_sresgproto='undef' +d_sresuproto='undef' +d_statblks='undef' +d_statfs_f_flags='undef' +d_statfs_s='undef' +d_statvfs='undef' +d_stdio_cnt_lval='undef' +d_stdio_ptr_lval='undef' +d_stdio_ptr_lval_nochange_cnt='undef' +d_stdio_ptr_lval_sets_cnt='undef' +d_stdio_stream_array='undef' +d_stdiobase='undef' +d_stdstdio='undef' +d_strchr='define' +d_strcoll='undef' +d_strctcpy='undef' +d_strerrm='strerror(e)' +d_strerror='define' +d_strerror_r='undef' +d_strftime='undef' +d_strlcat='undef' +d_strlcpy='undef' +d_strtod='define' +d_strtol='define' +d_strtold='undef' +d_strtoll='undef' +d_strtoq='undef' +d_strtoul='define' +d_strtoull='undef' +d_strtouq='undef' +d_strxfrm='undef' +d_suidsafe='undef' +d_symlink='undef' +d_syscall='undef' +d_syscallproto='undef' +d_sysconf='undef' +d_sysernlst='' +d_syserrlst='undef' +d_system='define' +d_tcgetpgrp='undef' +d_tcsetpgrp='undef' +d_telldir='define' +d_telldirproto='define' +d_time='define' +d_times='define' +d_tm_tm_gmtoff='undef' +d_tm_tm_zone='undef' +d_tmpnam_r='undef' +d_truncate='undef' +d_ttyname_r='undef' +d_tzname='undef' +d_u32align='define' +d_ualarm='undef' +d_umask='undef' +d_uname='undef' +d_union_semun='undef' +d_unordered='undef' +d_sitecustomize='undef' +d_usleep='define' +d_usleepproto='undef' +d_ustat='undef' +d_vendorarch='undef' +d_vendorbin='undef' +d_vendorlib='undef' +d_vfork='undef' +d_void_closedir='undef' +d_voidsig='undef' +d_voidtty='' +d_volatile='define' +d_vprintf='define' +d_wait4='undef' +d_waitpid='undef' +d_wcstombs='undef' +d_wctomb='undef' +d_writev='undef' +d_xenix='undef' +db_hashtype='u_int32_t' +db_prefixtype='size_t' +defvoidused=1 +direntrytype='struct dirent' +dlext='dll' +dlsrc='dl_symbian.xs' +doublesize='8' +drand01="((rand() & 0x7FFF) / (double) ((unsigned long)1 << 15))" +drand48_r_proto='0' +eagain='EAGAIN' +ebcdic='undef' +endgrent_r_proto='0' +endhostent_r_proto='0' +endnetent_r_proto='0' +endprotoent_r_proto='0' +endpwent_r_proto='0' +endservent_r_proto='0' +eunicefix=':' +exe_ext='.exe' +fflushNULL='undef' +fflushall='undef' +firstmakefile='makefile' +fpossize='4' +fpostype=fpos_t +freetype=void +full_ar=':' +getgrent_r_proto='0' +getgrgid_r_proto='0' +getgrnam_r_proto='0' +gethostbyaddr_r_proto='0' +gethostbyname_r_proto='0' +gethostent_r_proto='0' +getlogin_r_proto='0' +getnetbyaddr_r_proto='0' +getnetbyname_r_proto='0' +getnetent_r_proto='0' +getprotobyname_r_proto='0' +getprotobynumber_r_proto='0' +getprotoent_r_proto='0' +getpwent_r_proto='0' +getpwnam_r_proto='0' +getpwuid_r_proto='0' +getservbyname_r_proto='0' +getservbyport_r_proto='0' +getservent_r_proto='0' +getspnam_r_proto='0' +gidformat='"lu"' +gidsign='1' +gidsize='4' +gidtype=int +gmtime_r_proto='0' +groupstype=int +h_fcntl='false' +h_sysfile='true' +i16size='2' +i16type='short' +i32size='4' +i32type='long' +i64size='8' +i64type='int64_t' +i8size='1' +i8type='char' +i_arpainet='undef' +i_bsdioctl='' +i_crypt='undef' +i_db='undef' +i_dbm='undef' +i_dirent='define' +i_dld='undef' +i_dlfcn='undef' +i_fcntl='define' +i_float='undef' +i_fp='undef' +i_fp_class='undef' +i_gdbm='undef' +i_grp='undef' +i_ieeefp='undef' +i_inttypes='undef' +i_langinfo='undef' +i_libutil='undef' +i_limits='define' +i_locale='define' +i_machcthr='undef' +i_malloc='undef' +i_math='define' +i_memory='undef' +i_mntent='undef' +i_ndbm='undef' +i_netdb='define' +i_neterrno='undef' +i_netinettcp='undef' +i_niin='define' +i_poll='undef' +i_prot='undef' +i_pthread='undef' +i_pwd='define' +i_rpcsvcdbm='undef' +i_sfio='undef' +i_sgtty='undef' +i_shadow='undef' +i_socks='undef' +i_stdarg='define' +i_stddef='undef' +i_stdlib='define' +i_string='define' +i_sunmath='undef' +i_sysaccess='undef' +i_sysdir='undef' +i_sysfile='undef' +i_sysfilio='undef' +i_sysin='undef' +i_sysioctl='define' +i_syslog='undef' +i_sysmman='undef' +i_sysmode='undef' +i_sysmount='undef' +i_sysndir='undef' +i_sysparam='undef' +i_sysresrc='undef' +i_syssecrt='undef' +i_sysselct='undef' +i_syssockio='undef' +i_sysstat='define' +i_sysstatfs='undef' +i_sysstatvfs='undef' +i_systime='define' +i_systimek='undef' +i_systimes='define' +i_systypes='define' +i_sysuio='undef' +i_sysun='undef' +i_sysutsname='undef' +i_sysvfs='undef' +i_syswait='undef' +i_termio='undef' +i_termios='undef' +i_time='define' +i_unistd='define' +i_ustat='undef' +i_utime='undef' +i_values='undef' +i_varargs='undef' +i_varhdr='stdarg.h' +i_vfork='undef' +ignore_versioned_solibs='y' +inc_version_list='0' +inc_version_list_init='0' +installprefix='\\system' +installprefixexp='\\system' +installsitearch='\\system\\libs\\perl\\siteperl\\x.y.z\\thumb-symbian' +installsitelib='\\system\\libs\\perl\\siteperl\\x.y.z' +installstyle='lib\\perl5' +installusrbinperl='undef' +intsize='4' +ivdformat='"ld"' +ivsize='4' +ivtype='long' +lib_ext='.a' +lddlflags='' +ld=':' +ldflags='' +libc='stdlib' +libm_lib_version='0' +libperl='libperl.a' +localtime_r_proto='0' +longdblsize=8 +longlongsize=8 +longsize='4' +lseeksize=4 +lseektype=int +make='make' +malloctype='int*' +malloctype='void *' +modetype='mode_t' +modetype=int +multiarch='undef' +myarchname='thumb-symbian' +myuname='symbian' +need_va_copy='undef' +netdb_hlen_type='int' +netdb_host_type='const char *' +netdb_name_type='const char *' +netdb_net_type='unsigned long' +nroff='nroff' +nv_preserves_uv_bits='0' +nveformat='"e"' +nvfformat='"f"' +nvgformat='"g"' +nvsize='8' +nvtype='double' +o_nonblock='O_NONBLOCK' +obj_ext='.o' +old_pthread_create_joinable='' +optimize='-O2' +orderlib='false' +osname='symbian' +osvers='7.0s' +otherlibdirs='' +path_sep=';'; +phostname='hostname' +pidtype='int' +pm_apiversion='5.005' +privlib='\\system\\libs\\perl\\x.y.z' +privlibexp='\\system\\libs\\perl\\x.y.z' +procselfexe='' +prototype='undef' +ptrsize='4' +quadkind='4' +quadtype='int64_t' +randbits='48' +randfunc='drand48' +random_r_proto='0' +randseedtype='int' +ranlib=':' +rd_nodata='-1' +readdir64_r_proto='0' +readdir_r_proto='0' +sPRIEUldbl='"llE"' +sPRIFUldbl='"llF"' +sPRIGUldbl='"llG"' +sPRIXU64='"LX"' +sPRId64='"Ld"' +sPRIeldbl='' +sPRIfldbl='' +sPRIgldbl='' +sPRIi64='"Li"' +sPRIo64='"Lo"' +sPRIu64='"Lu"' +sPRIx64='"Lx"' +sSCNfldbl='' +sched_yield='sched_yield()' +scriptdir='\\system\\apps\\perl' +scriptdirexp='\\system\\apps\\perl' +sdkvers='' +seedfunc='srand' +selectminbits='32' +selecttype=int +setgrent_r_proto='0' +sethostent_r_proto='0' +setlocale_r_proto='0' +setnetent_r_proto='0' +setprotoent_r_proto='0' +setpwent_r_proto='0' +setservent_r_proto='0' +shmattype='void *' +shortsize=2 +sig_name_init='0' +sig_num_init='0' +sig_size='1' +signal_t=void +sitearch='\\system\\libs\\perl\\siteperl\\x.y.z\\thumb-symbian' +sitearchexp='\\system\\libs\\perl\\siteperl\\x.y.z\\thumb-symbian' +sitelib='\\system\\libs\\perl\\siteperl\\x.y.z' +sitelib_stem='\\system\\libs\\perl' +sitelibexp='\\system\\libs\\perl\\siteperl\\x.y.z' +siteprefix='\\system' +siteprefixexp='\\system' +sizesize=4 +sizetype=size_t +so='o' +socksizetype='unsigned int' +srand48_r_proto='0' +srandom_r_proto='0' +ssizetype=int +stdchar=char +stdio_base='((fp)->_IO_read_base)' +stdio_bufsiz='((fp)->_IO_read_end - (fp)->_IO_read_base)' +stdio_cnt='((fp)->_IO_read_end - (fp)->_IO_read_ptr)' +stdio_filbuf='' +stdio_ptr='((fp)->_IO_read_ptr)' +stdio_stream_array='' +strerror_r_proto='0' +targetarch='thumb-symbian' +timetype=time_t +tmpnam_r_proto='0' +touch='touch' +ttyname_r_proto='0' +u16size='2' +u16type='unsigned short' +u32size='4' +u32type='unsigned long' +u64size='8' +u64type='uint64_t' +u8size='1' +u8type='unsigned char' +uidformat='"lu"' +uidsign='1' +uidsize='4' +uidtype=int +uquadtype='uint64_t' +use5005threads='undef' +use64bitall='undef' +use64bitint='undef' +usecrosscompile='define' +usedl='undef' +usefaststdio='undef' +useithreads='undef' +uselargefiles='undef' +uselongdouble='undef' +usemallocwrap='define' +usemorebits='undef' +usemultiplicity='undef' +usemymalloc='n' +usenm='false' +useopcode='true' +useperlio='define' +useposix='true' +usereentrant='undef' +userelocatableinc='undef' +usesfio='false' +useshrplib='false' +usesitecustomize='undef' +usesocks='undef' +usethreads='undef' +usevendorprefix='n' +usevfork='false' +uvXUformat='"lX"' +uvoformat='"lo"' +uvsize='4' +uvtype='unsigned long' +uvuformat='"lu"' +vendorlib_stem='' +vendorlib='' +vendorlibexp='' +vendorarch='' +vendorarchexp='' +vendorprefix='' +vendorprefixexp='' +version='x.y.z' +uvxformat='"lx"' +versiononly='undef' +voidflags=1 +xs_apiversion='5.008' diff --git a/symbian/cwd.pl b/symbian/cwd.pl new file mode 100644 index 0000000000..d3272d2de5 --- /dev/null +++ b/symbian/cwd.pl @@ -0,0 +1,6 @@ +use strict; +use Cwd; +my $CWD = getcwd(); +$CWD =~ s!^C:!!i; +$CWD =~ s!/!\\!g; +$CWD; diff --git a/symbian/demo_pl b/symbian/demo_pl new file mode 100644 index 0000000000..fbba5f4bf9 --- /dev/null +++ b/symbian/demo_pl @@ -0,0 +1,128 @@ +#!/usr/bin/perl -w + +# +# demo_pl +# +# A "self-extracting archive" for some demo scripts. +# +# hello - the classic +# helloyou - advanced classic +# httpget1 - simple sockets +# httpget2 - simple sockets done complex +# md5 - core extension +# time - system call +# times - more system calls +# + +use strict; + +unless (@ARGV && $ARGV[0] =~ /^(?:list|extract|cleanup)$/) { + die "$0: Usage: $0 [list|extract|cleanup]\n"; +} + +my $action = shift; +my $list = $action eq 'list'; +my $extract = $action eq 'extract'; +my $cleanup = $action eq 'cleanup'; + +my $fh; +while (<DATA>) { + if (/^-- (.+\.pl)$/) { + if ($cleanup) { + print "Deleting $1\n"; + unlink $1 or warn "$0: $1: $!\n"; + } elsif ($extract) { + defined $fh && close($fh); + open($fh, ">$1") or die "$0: '$1': $!\n"; + print "Extracting $1\n"; + } elsif ($list) { + print "$1\n"; + } + } else { + print $fh $_ if $extract; + } +} +defined $fh && close($fh); +exit(0); +__END__ +-- hello.pl +print "hello world!\n"; +-- helloyou.pl +print "What is your name?\n"; +chomp(my $name = <STDIN>); +print "Hello, $name!\n"; +print "Amazing fact #1:\n"; +printf "Your name has\n%d character%s!\n", + length($name), length($name) == 1 ? "" : "s"; +print "Amazing fact #2:\n"; +printf "Your name is\n%s backwards!\n", scalar reverse $name; +-- httpget1.pl +print "(Using plain sockets)\n"; +use Socket; +print "Host? "; +my $host = <STDIN>; +chomp($host); +$host = 'www.nokia.com' unless length $host; +my $port = 80; +my $iaddr = inet_aton($host) || die "no host: $host"; +my $paddr = sockaddr_in($port, $iaddr); +my $proto = getprotobyname("tcp"); +socket(S, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; +connect(S, $paddr) || die "connect: $!"; +print "$host:$port:\nConnected.\n"; +select(S); $| = 1; select(STDOUT); +print S "GET / HTTP/1.0\012\012" || die "GET /: $!"; +my @line; +print "Receiving...\n"; +while (my $line = <S>) { + push @line, $line; +} +close(S) || die "close: $!"; +printf "Got %d lines.\n", scalar @line; +-- httpget2.pl +use IO::Socket; +print "(Using IO::Socket)\n"; +print "Host? "; +my $host = <STDIN>; +chomp($host); +$host = 'www.nokia.com' unless length $host; +my $port = 80; +my $remote = + IO::Socket::INET->new(Proto => "tcp", + PeerAddr => $host, + PeerPort => $port); +print "$host:$port:\nConnected.\n"; +select($remote); $| = 1; select(STDOUT); +print $remote "GET / HTTP/1.0\012\012" || die "GET /: $!"; +my @line; +print "Receiving...\n"; +while (my $line = <$remote>) { + push @line, $line; +} +close($remote) || die "close: $!"; +printf "Got %d lines.\n", scalar @line; +-- md5.pl +use Digest::MD5 'md5_hex'; +print "(Using Digest::MD5)\nMD5 of 'Perl' is:\n"; +print md5_hex('Perl'), "\n"; +-- time.pl +print "Running in $^O\n"; +print scalar localtime, "\n"; +-- times.pl +use Time::HiRes qw(time sleep); +print CORE::time(), "\n"; +print "Hires\n"; +print time(), "\n"; +print "Sleep 1.5 s...\n"; +sleep(1.5); +print time(), "\n"; +print "To one million...\n"; +my $t0 = time(); +print $t0, "\n"; +print "Cpu ", scalar times(), "\n"; +for(my $i = 0; $i < 1e6; $i++) {} +print "Cpu ", scalar times(), "\n"; +my $t1 = time(); +print $t1, "\n"; +print "Wall ", $t1 - $t0, "\n"; + diff --git a/symbian/install.cfg b/symbian/install.cfg new file mode 100644 index 0000000000..8cc7b10b9c --- /dev/null +++ b/symbian/install.cfg @@ -0,0 +1,108 @@ +# install.cfg +# +# Copyright (c) 2004-2005 Nokia. All Rights Reserved. +# +# This file details what library files to include in the perlXYZlib.sis, +# and what extensions to build for the perlXYZext.sis. +# The lines beginning with "lib" are # included as-is from the lib/. +# The lines beginning with "ext" tell either how to build and package +# the extensions - or not. + +# +# Libraries. +# +lib AnyDBM_File.pm +lib AutoLoader.pm +lib base.pm +lib Benchmark.pm +lib Carp.pm +lib Carp/Heavy.pm +lib Cwd.pm +lib constant.pm +lib DBM_Filter.pm +lib Digest/base.pm +lib DirHandle.pm +lib Exporter.pm +lib Exporter/Heavy.pm +lib File/Basename.pm +lib File/Compare.pm +lib File/Copy.pm +lib File/DosGlob.pm +lib File/Find.pm +lib File/Path.pm +lib File/Spec.pm +lib File/Spec/Unix.pm +lib File/Spec/Win32.pm +lib File/Temp.pm +lib FileHandle.pm +lib Filter/Simple.pm +lib if.pm +lib integer.pm +lib lib.pm +lib Net/Cmd.pm +lib Net/Config.pm +lib Net/Domain.pm +lib Net/FTP.pm +lib Net/FTP/A.pm +lib Net/FTP/E.pm +lib Net/FTP/I.pm +lib Net/FTP/L.pm +lib Net/FTP/dataconn.pm +lib Net/NNTP.pm +lib Net/Netrc.pm +lib Net/Ping.pm +lib Net/POP3.pm +lib Net/SMTP.pm +lib Net/Time.pm +lib NEXT.pm +lib overload.pm +lib SelectSaver.pm +lib strict.pm +lib Symbol.pm +lib UNIVERSAL.pm +# lib utf8.pm +# lib utf8_heavy.pl +lib vars.pm +lib warnings.pm +lib warnings/register.pm +# +# Extensions. +# +ext attrs +ext Cwd +ext Data/Dumper +ext Devel/Peek +ext Digest/MD5 +ext Errno +ext Fcntl CONST +ext File/Glob CONST +ext Filter/Util/Call +ext IO +ext List/Util +ext MIME/Base64 +ext PerlIO/scalar +ext PerlIO/via +ext SDBM_File -sdbm/db?.c -sdbm/util.c +ext Socket CONST +ext Storable +ext Time/HiRes CONST +ext XSLoader +# ext B ERROR +# ext ByteLoader byterun.c ERROR VERSION +# ext Devel/DProf nonconst +# ext Devel/PPPort PORT +# ext Encode nonconst Encode/encode.h def_t.c encengine.c +# ext I18N/Langinfo PORT +# ext IPC/SysV PORT +# ext Opcode ERROR +# ext PerlIO/encoding Encode +# ext POSIX CONST USELESS +# ext re ERROR +# ext Sys/Hostname PORT +# ext Sys/Syslog PORT +# ext threads PORT +# ext threads/shared PORT +# ext Unicode/Normalize nonconst +# ext XS/APItest USELESS +# ext XS/Typemap nonconst USELESS + diff --git a/symbian/makesis.pl b/symbian/makesis.pl new file mode 100644 index 0000000000..1ee5e8dc2f --- /dev/null +++ b/symbian/makesis.pl @@ -0,0 +1,185 @@ +#!/usr/bin/perl -w + +# Copyright (c) 2004-2005 Nokia. All rights reserved. + +use strict; +use lib "symbian"; + +do "sanity.pl"; + +my %VERSION = %{ do "version.pl" }; +my $VERSION = "$VERSION{REVISION}$VERSION{VERSION}$VERSION{SUBVERSION}"; +my $R_V_SV = "$VERSION{REVISION}.$VERSION{VERSION}.$VERSION{SUBVERSION}"; + +my $SDK = do "sdk.pl"; +my $UID = do "uid.pl"; +my %PORT = %{ do "port.pl" }; + +my $ARM = 'thumb'; # TODO +my $S60SK = $ENV{S60SDK}; # from sdk.pl + +my $UREL = $ENV{UREL}; # from sdk.pl +$UREL =~ s/-ARM-/$ARM/; + +my $app = '!:\System\Apps\Perl'; +my $lib = '!:\System\Libs'; + +my @target = @ARGV + ? @ARGV + : ( + "miniperl", "perl", + "perl${VERSION}dll", "perl${VERSION}lib", + "perl${VERSION}ext" + ); + +my %suffix; +@suffix{ "miniperl", "perl", "perl$VERSION" } = ( "exe", "exe", "dll", ); + +for my $target (@target) { + $target = "perl${VERSION}" if $target eq "perl${VERSION}dll"; + + my %copy; + my $pkg = "$target.pkg"; + print "\nCreating $pkg...\n"; + + my $suffix = $suffix{$target} || ""; + my $dst = $suffix eq "dll" ? $lib : $app; + + my $srctarget = "$UREL\\$target.$suffix"; + + if ( $target =~ /^(miniperl|perl|perl${VERSION}(?:dll)?)$/ ) { + $copy{$srctarget} = "$dst\\$target.$suffix"; + print "\t$target.$suffix\n"; + } + if ( $target eq "perl${VERSION}lib" ) { + print "Libraries...\n"; + + print "\tConfig.pm\n"; + $copy{"lib\\Config.pm"} = + "$lib\\Perl\\$R_V_SV\\thumb-symbian\\Config.pm"; + + print "\tConfig_heavy.pl\n"; + $copy{"xlib\\symbian\\Config_heavy.pl"} = + "$lib\\Perl\\$R_V_SV\\thumb-symbian\\Config_heavy.pl"; + + print "\tDynaLoader.pm\n"; + $copy{"ext\\DynaLoader\\DynaLoader.pm"} = + "$lib\\Perl\\$R_V_SV\\DynaLoader.pm"; + + print "\tErrno.pm\n"; + $copy{"ext\\Errno\\Errno.pm"} = "$lib\\Perl\\$R_V_SV\\Errno.pm"; + + open( my $cfg, "symbian/install.cfg" ) + or die "$!: symbian/install.cfg: $!\n"; + while (<$cfg>) { + next unless /^lib\s+(.+)/; + chomp; + my $f = $1; + $f =~ s:/:\\:g; + $copy{"lib\\$f"} = "$lib\\Perl\\$R_V_SV\\$f"; + print "\t$f\n"; + } + close($cfg); + } + + if ( $target eq "perl${VERSION}ext" ) { + my @lst = glob("symbian/*.lst"); + print "Extensions...\n"; + print "\t(none found)\n" unless @lst; + for my $lst (@lst) { + $lst =~ m:^symbian/(.+)\.:; + my $ext = $1; + $ext =~ s!-!::!g; + print "\t$ext\n"; + if ( open( my $pkg, $lst ) ) { + while (<$pkg>) { + if (m!^"(.+)"-"(.+)"$!) { + my ( $src, $dst ) = ( $1, $2 ); + $copy{$src} = $dst; + } + else { + warn "$0: $lst: $.: unknown syntax\n"; + } + } + close($pkg); + } + else { + warn "$0: $lst: $!\n"; + } + } + } + + for my $file ( keys %copy ) { + warn "$0: $file does not exist\n" unless -f $file; + } + + my @copy = map { qq["$_"-"$copy{$_}"] } sort keys %copy; + my $copy = join( "\n", @copy ); + + my %UID = ( + "miniperl" => 0, + "perl" => 0, + "perl${VERSION}" => $UID + 0, + "perl${VERSION}dll" => $UID + 0, + "perl${VERSION}ext" => $UID + 1, + "perl${VERSION}lib" => $UID + 2, + + # app = + 3 + # rec = + 4 + ); + + die "$0: target has no UID\n" unless defined $UID{$target}; + + my $uid = sprintf( "0x%08X", $UID{$target} ); + + my ( $MAJOR, $MINOR, $PATCH ) = ( 0, 0, 0 ); + + if ( $target =~ m:^perl$VERSION(dll|ext|lib)?$: ) { + my $pkg = defined $1 ? $1 : "dll"; + $MAJOR = $PORT{$pkg}->{MAJOR}; + $MINOR = $PORT{$pkg}->{MINOR}; + $PATCH = $PORT{$pkg}->{PATCH}; + } + + die "$0: Bad version for $target\n" + unless defined $MAJOR + && ( $MAJOR eq 0 || $MAJOR > 0 ) + && defined $MINOR + && ( $MINOR eq 0 || $MINOR > 0 ) + && defined $PATCH + && ( $PATCH eq 0 || $PATCH > 0 ); + + open PKG, ">$pkg" or die "$0: failed to create $pkg: $!\n"; + print PKG <<__EOF__; +; \u$target installation script +; +; The supported languages +&EN; +; +; The installation name and header data +; +#{"\u$target"},($uid),$MAJOR,$MINOR,$PATCH +; +; Private key and certificate (unused) +; +;* "\u$target.key", "\u$target.cer" +; +; Supports Series60 v0.9 +(0x101F6F88), 0, 0, 0, {"Series60ProductID"} +; The files to install +; +$copy +__EOF__ + close PKG; + + print "Created $pkg\n"; + + print "Running makesis...\n"; + + unlink("$target.sis"); + + system("makesis $pkg") == 0 + || die "$0: makesis $pkg failed: $!\n"; +} + +exit(0); diff --git a/symbian/port.pl b/symbian/port.pl new file mode 100644 index 0000000000..affb42c461 --- /dev/null +++ b/symbian/port.pl @@ -0,0 +1,6 @@ +{ + dll => { MAJOR => 0, MINOR => 1, PATCH => 0 }, + ext => { MAJOR => 0, MINOR => 1, PATCH => 0 }, + lib => { MAJOR => 0, MINOR => 1, PATCH => 0 }, +} + diff --git a/symbian/sanity.pl b/symbian/sanity.pl new file mode 100644 index 0000000000..eb50244dde --- /dev/null +++ b/symbian/sanity.pl @@ -0,0 +1,28 @@ +use strict; + +if (exists $ENV{'!C:'}) { + print "You are running this under Cygwin, aren't you?\n"; + print "I'm sorry but only cmd.exe will work.\n"; + exit(1); +} + +if (# SDK 2.x + $ENV{PATH} !~ m!c:\\program files\\common files\\symbian\\tools!i + && + # SDK 1.2 + $ENV{PATH} !~ m!c:\\symbian\\6.1\\shared\\epoc32\\tools!i) { + print "I think you have not installed the Symbian SDK.\n"; + exit(1); +} + +unless (-f "symbian/symbianish.h") { + print "You must run this in the top level directory.\n"; + exit(1); +} + +if ($] < 5.008) { + print "You must configure with Perl 5.8 or later.\n"; + exit(1); +} + +1; diff --git a/symbian/sdk.pl b/symbian/sdk.pl new file mode 100644 index 0000000000..1dc4d2f552 --- /dev/null +++ b/symbian/sdk.pl @@ -0,0 +1,48 @@ +use strict; + +my $SDK; +my $WIN; + +if ($ENV{PATH} =~ m!\\Symbian\\(.+?)\\gcc\\bin!) { + my $cc = $1; + $WIN = $cc =~ m!_CW!i ? 'winscw' : 'wins'; + $ENV{WIN} = $WIN; + if ($cc =~ m!Series60_v20!) { + $ENV{S60SDK} = '2.0'; + } elsif ($cc =~ m!Series60_v21!) { + $ENV{S60SDK} = '2.1'; + } elsif ($cc =~ m!S60_2nd_FP2!) { + $ENV{S60SDK} = '2.6'; + } +} + +if (open(GCC, "gcc -v 2>&1|")) { + while (<GCC>) { + if (/Reading specs from ((?:C:)?\\Symbian.+?)\\Epoc32\\/i) { + $SDK = $1; + # The S60SDK tells the Series 60 SDK version. + if ($SDK eq 'C:\Symbian\6.1\Shared') { # Visual C. + $SDK = 'C:\Symbian\6.1\Series60'; + $ENV{S60SDK} = '1.2'; + } elsif ($SDK eq 'C:\Symbian\Series60_1_2_CW') { # CodeWarrior. + $ENV{S60SDK} = '1.2'; + } + last; + } + } + close GCC; +} else { + die "$0: failed to run gcc: $!\n"; +} + +my $UARM = $ENV{UARM} ? $ENV{UARM} : "urel"; +my $UREL = "$SDK\\epoc32\\release\\-ARM-\\$UARM"; +if ($SDK eq 'C:\Symbian\6.1\Series60' && $ENV{WIN} eq 'winscw') { + $UREL = "C:\\Symbian\\Series60_1_2_CW\\epoc32\\release\\-ARM-\\urel"; +} +$ENV{UREL} = $UREL; +$ENV{UARM} = $UARM; + +die "$0: failed to locate the Symbian SDK\n" unless defined $SDK; + +$SDK; diff --git a/symbian/symbian_dll.cpp b/symbian/symbian_dll.cpp new file mode 100644 index 0000000000..92a06b883f --- /dev/null +++ b/symbian/symbian_dll.cpp @@ -0,0 +1,20 @@ +/* + * symbian_dll.cpp + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#define SYMBIAN_DLL_CPP +#include <e32base.h> +#include "PerlBase.h" + +EXPORT_C GLDEF_C TInt E32Dll(TDllReason /*aReason*/) { return KErrNone; } + +extern "C" { + EXPORT_C void* symbian_get_vars(void) { return Dll::Tls(); } + EXPORT_C void symbian_set_vars(const void *p) { Dll::SetTls((TAny*)p); } + EXPORT_C void symbian_unset_vars(void) { Dll::SetTls(0); } +} + diff --git a/symbian/symbian_proto.h b/symbian/symbian_proto.h new file mode 100644 index 0000000000..f50de34af8 --- /dev/null +++ b/symbian/symbian_proto.h @@ -0,0 +1,72 @@ +/* + * symbian_proto.h + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#ifndef SYMBIAN_PROTO_H +#define SYMBIAN_PROTO_H + +#include <sys/types.h> +#include <sys/times.h> + +#if defined(PERL_CORE) || defined(PERL_EXT) + +/* We can't include the <string.h> unconditionally + * since it has prototypes conflicting with the gcc builtins. */ +extern void *memchr(const void *s, int c, size_t n); +#ifndef DL_SYMBIAN_XS +/* dl_symbian.xs needs to see the C++ prototype of memset() instead */ +extern void *memset(void *s, int c, size_t n); +extern size_t strlen(const char *s); +#endif +extern void *memmove(void *dst, const void *src, size_t n); +extern char *strcat(char *dst, const char *src); +extern char *strchr(const char *s, int c); +extern char *strerror(int errnum); +extern int strncmp(const char *s1, const char *s2, size_t n); +extern char *strrchr(const char *s, int c); + +extern int setmode(int fd, long flags); + +#ifndef __GNUC__ +#define memcpy _e32memcpy /* GCC intrinsic */ +extern void *memcpy(const void *s1, const void *s2, size_t n); +extern int strcmp(const char *s1, const char *s2); +extern char* strcpy(char *dst, const char *src); +extern char* strncpy(char *dst, const char *src, size_t n); +#endif + +#endif /* PERL_CORE || PERL_EXT */ + +#if defined(SYMBIAN_DLL_CPP) || defined(SYMBIAN_UTILS_CPP) || defined(PERLBASE_CPP) +# define PERL_SYMBIAN_START_EXTERN_C extern "C" { +# define PERL_SYMBIAN_EXPORT_C EXPORT_C +# define PERL_SYMBIAN_END_EXTERN_C } +#else +# define PERL_SYMBIAN_START_EXTERN_C +# define PERL_SYMBIAN_EXPORT_C +# define PERL_SYMBIAN_END_EXTERN_C +#endif + +PERL_SYMBIAN_START_EXTERN_C +PERL_SYMBIAN_EXPORT_C int symbian_sys_init(int *argcp, char ***argvp); +PERL_SYMBIAN_EXPORT_C void* symbian_get_vars(void); +PERL_SYMBIAN_EXPORT_C void symbian_set_vars(const void *); +PERL_SYMBIAN_EXPORT_C void symbian_unset_vars(void); +PERL_SYMBIAN_EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n); +PERL_SYMBIAN_EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n); +PERL_SYMBIAN_EXPORT_C char* symbian_get_error_string(const int error); +PERL_SYMBIAN_EXPORT_C void symbian_sleep_usec(const long usec); +PERL_SYMBIAN_EXPORT_C int symbian_get_cpu_time(long* sec, long* usec); +PERL_SYMBIAN_EXPORT_C clock_t symbian_times(struct tms* buf); +PERL_SYMBIAN_EXPORT_C int symbian_usleep(unsigned int usec); +PERL_SYMBIAN_EXPORT_C int symbian_do_aspawn(void* vreally, void *vmark, void* sp); +PERL_SYMBIAN_EXPORT_C int symbian_do_spawn(const char* command); +PERL_SYMBIAN_EXPORT_C int symbian_do_spawn_nowait(const char* command); +PERL_SYMBIAN_END_EXTERN_C + +#endif /* !SYMBIAN_PROTO_H */ + diff --git a/symbian/symbian_stubs.c b/symbian/symbian_stubs.c new file mode 100644 index 0000000000..1505698703 --- /dev/null +++ b/symbian/symbian_stubs.c @@ -0,0 +1,112 @@ +/* + * symbian_stubs.c + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#include "EXTERN.h" +#include "perl.h" +#include "symbian_stubs.h" + +static int setENOSYS(void) { errno = ENOSYS; return -1; } + +uid_t getuid(void) { return setENOSYS(); } +gid_t getgid(void) { return setENOSYS(); } +uid_t geteuid(void) { return setENOSYS(); } +gid_t getegid(void) { return setENOSYS(); } + +int setuid(uid_t uid) { return setENOSYS(); } +int setgid(gid_t gid) { return setENOSYS(); } +int seteuid(uid_t uid) { return setENOSYS(); } +int setegid(gid_t gid) { return setENOSYS(); } + +int execv(const char* path, char* const argv []) { return setENOSYS(); } +int execvp(const char* path, char* const argv []) { return setENOSYS(); } + +#ifndef USE_PERLIO +FILE *popen(const char *command, const char *mode) { return 0; } +int pclose(FILE *stream) { return setENOSYS(); } +#endif +int pipe(int fd[2]) { return setENOSYS(); } + +int setmode(int fd, long flags) { return -1; } + +_sig_func_ptr signal(int signum, _sig_func_ptr handler) { return (_sig_func_ptr)setENOSYS(); } +int kill(pid_t pid, int signum) { return setENOSYS(); } +pid_t wait(int *status) { return setENOSYS(); } + +#if PERL_VERSION <= 8 +void Perl_my_setenv(pTHX_ char *var, char *val) { } +#else +void Perl_my_setenv(pTHX_ const char *var, const char *val) { } +#endif + +bool Perl_do_exec(pTHX_ char *cmd) { return FALSE; } +bool Perl_do_exec3(pTHX_ char *cmd, int fd, int flag) { return FALSE; } + +int Perl_do_spawn(pTHX_ char *cmd) { return symbian_do_spawn(cmd); } +int Perl_do_aspawn(pTHX_ SV *really, SV** mark, SV **sp) { return symbian_do_aspawn(really, mark, sp); } + +static const struct protoent protocols[] = { + { "tcp", 0, 6 }, + { "udp", 0, 17 } +}; + +/* The protocol field (the last) is left empty to save both space + * and time because practically all services have both tcp and udp + * allocations in IANA. */ +static const struct servent services[] = { + { "http", 0, 80, 0 }, /* Optimization. */ + { "https", 0, 443, 0 }, + { "imap", 0, 143, 0 }, + { "imaps", 0, 993, 0 }, + { "smtp", 0, 25, 0 }, + { "irc", 0, 194, 0 }, + + { "ftp", 0, 21, 0 }, + { "ssh", 0, 22, 0 }, + { "tftp", 0, 69, 0 }, + { "pop3", 0, 110, 0 }, + { "sftp", 0, 115, 0 }, + { "nntp", 0, 119, 0 }, + { "ntp", 0, 123, 0 }, + { "snmp", 0, 161, 0 }, + { "ldap", 0, 389, 0 }, + { "rsync", 0, 873, 0 }, + { "socks", 0, 1080, 0 } +}; + +struct protoent* getprotobynumber(int number) { + int i; + for (i = 0; i < sizeof(protocols)/sizeof(struct protoent); i++) + if (protocols[i].p_proto == number) + return (struct protoent*)(&(protocols[i])); + return 0; +} + +struct protoent* getprotobyname(const char* name) { + int i; + for (i = 0; i < sizeof(protocols)/sizeof(struct protoent); i++) + if (strcmp(name, protocols[i].p_name) == 0) + return (struct protoent*)(&(protocols[i])); + return 0; +} + +struct servent* getservbyname(const char* name, const char* proto) { + int i; + for (i = 0; i < sizeof(services)/sizeof(struct servent); i++) + if (strcmp(name, services[i].s_name) == 0) + return (struct servent*)(&(services[i])); + return 0; +} + +struct servent* getservbyport(int port, const char* proto) { + int i; + for (i = 0; i < sizeof(services)/sizeof(struct servent); i++) + if (services[i].s_port == port) + return (struct servent*)(&(services[i])); + return 0; +} + diff --git a/symbian/symbian_stubs.h b/symbian/symbian_stubs.h new file mode 100644 index 0000000000..ab6b9616cd --- /dev/null +++ b/symbian/symbian_stubs.h @@ -0,0 +1,22 @@ +/* + * symbian_stubs.h + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#ifndef PERL_SYMBIAN_STUBS_H +#define PERL_SYMBIAN_STUBS_H + +int execv(const char* path, char* const argv []); +int execvp(const char* path, char* const argv []); + +#ifndef USE_PERLIO +FILE *popen(const char *command, const char *mode); +int pclose(FILE *stream); +#endif +int pipe(int fd[2]); + +#endif /* PERL_SYMBIAN_STUBS_H */ + diff --git a/symbian/symbian_utils.cpp b/symbian/symbian_utils.cpp new file mode 100644 index 0000000000..16e911c81e --- /dev/null +++ b/symbian/symbian_utils.cpp @@ -0,0 +1,299 @@ +/* + * symbian_utils.cpp + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#define SYMBIAN_UTILS_CPP +#include <e32base.h> +#include <e32std.h> +#include <textresolver.h> +#include <utf.h> +#include <hal.h> + +#include <string.h> +#include <ctype.h> + +#include "PerlBase.h" + +extern "C" { + EXPORT_C int symbian_sys_init(int *argcp, char ***argvp) + { +#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ + dVAR; +#endif + (void)times(&PL_timesbase); + return 0; + } + EXPORT_C SSize_t symbian_read_stdin(const int fd, char *b, int n) + { +#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ + dVAR; +#endif + return ((CPerlBase*)PL_appctx)->ConsoleRead(fd, b, n); + } + EXPORT_C SSize_t symbian_write_stdout(const int fd, const char *b, int n) + { +#ifdef PERL_GLOBAL_STRUCT /* Avoid unused variable warning. */ + dVAR; +#endif + return ((CPerlBase*)PL_appctx)->ConsoleWrite(fd, b, n); + } + static const char NullErr[] = ""; + EXPORT_C char* symbian_get_error_string(const TInt error) + { + dTHX; + if (error >= 0) + return strerror(error); + CTextResolver* textResolver = CTextResolver::NewL(); + CleanupStack::PushL(textResolver); + TBuf<KErrorResolverMaxTextLength> buf16; + TBuf8<KErrorResolverMaxTextLength> buf8; + if (error != KErrNone) + buf16 = textResolver->ResolveError(error); + if (buf16.Length()) { + if (CnvUtfConverter::ConvertFromUnicodeToUtf8(buf8, buf16) != + KErrNone) { + CleanupStack::PopAndDestroy(textResolver); + return (char*)NullErr; + } + } + SV* sv = Perl_get_sv(aTHX_ "\005", TRUE); /* $^E or ${^OS_ERROR} */ + if (!sv) + return (char*)NullErr; + sv_setpv(sv, (const char *)buf8.PtrZ()); + SvUTF8_on(sv); + CleanupStack::PopAndDestroy(textResolver); + return SvPV_nolen(sv); + } + EXPORT_C void symbian_sleep_usec(const long usec) + { + User::After((TTimeIntervalMicroSeconds32) usec); + } +#define PERL_SYMBIAN_CLK_TCK 100 + EXPORT_C int symbian_get_cpu_time(long* sec, long* usec) + { + // The RThread().GetCpuTime() does not seem to work? + // (it always returns KErrNotSupported) + // TTimeIntervalMicroSeconds ti; + // TInt err = me.GetCpuTime(ti); + dTHX; + TInt periodus; /* tick period in microseconds */ + if (HAL::Get(HALData::ESystemTickPeriod, periodus) != KErrNone) + return -1; + TUint tick = User::TickCount(); + if (PL_timesbase.tms_utime == 0) { + PL_timesbase.tms_utime = tick; + PL_clocktick = PERL_SYMBIAN_CLK_TCK; + } + tick -= PL_timesbase.tms_utime; + TInt64 tickus = TInt64(tick) * TInt64(periodus); + TInt64 tmps = tickus / 1000000; + if (sec) *sec = tmps.Low(); + if (usec) *usec = tickus.Low() - tmps.Low() * 1000000; + return 0; + } + EXPORT_C int symbian_usleep(unsigned int usec) + { + if (usec >= 1000000) { + errno = EINVAL; + return -1; + } + symbian_sleep_usec((const long) usec); + return 0; + } +#define SEC_USEC_TO_CLK_TCK(s, u) \ + (((s) * PERL_SYMBIAN_CLK_TCK) + (u / (1000000 / PERL_SYMBIAN_CLK_TCK))) + EXPORT_C clock_t symbian_times(struct tms *tmsbuf) + { + long s, u; + if (symbian_get_cpu_time(&s, &u) == -1) { + errno = EINVAL; + return -1; + } else { + tmsbuf->tms_utime = SEC_USEC_TO_CLK_TCK(s, u); + tmsbuf->tms_stime = 0; + tmsbuf->tms_cutime = 0; + tmsbuf->tms_cstime = 0; + return tmsbuf->tms_utime; + } + } + class CE32ProcessWait : public CActive + { + public: + CE32ProcessWait() : CActive(EPriorityStandard) { + CActiveScheduler::Add(this); + } +#ifdef __WINS__ + TInt Wait(RThread& aProcess) +#else + TInt Wait(RProcess& aProcess) +#endif + { + aProcess.Logon(iStatus); + aProcess.Resume(); + SetActive(); + CActiveScheduler::Start(); + return iStatus.Int(); + } + private: + void DoCancel() {;} + void RunL() { + CActiveScheduler::Stop(); + } + CActiveSchedulerWait iWait; + }; + class CSpawnIoRedirect : public CBase + { + public: + CSpawnIoRedirect(); + // NOTE: there is no real implementation of I/O redirection yet. + protected: + private: + }; + CSpawnIoRedirect::CSpawnIoRedirect() + { + } + typedef enum { + ESpawnNone = 0x00000000, + ESpawnWait = 0x00000001 + } TSpawnFlag; + static int symbian_spawn(const TDesC& aFilename, + const TDesC& aCommand, + const TSpawnFlag aFlag, + const CSpawnIoRedirect& aIoRedirect) { + TInt error = KErrNone; +#ifdef __WINS__ + const TInt KStackSize = 0x1000; + const TInt KHeapMin = 0x1000; + const TInt KHeapMax = 0x100000; + RThread proc; + RLibrary lib; + HBufC* command = aCommand.Alloc(); + error = lib.Load(aFilename); + if (error == KErrNone) { + TThreadFunction func = (TThreadFunction)(lib.Lookup(1)); + if (func) + error = proc.Create(aFilename, + func, + KStackSize, + (TAny*)command, + &lib, + RThread().Heap(), + KHeapMin, + KHeapMax, + EOwnerProcess); + else + error = KErrNotFound; + lib.Close(); + } + else + delete command; +#else + RProcess proc; + error = proc.Create(aFilename, aCommand); +#endif + if (error == KErrNone) { + if ((TInt)aFlag & (TInt)ESpawnWait) { + CE32ProcessWait* w = new CE32ProcessWait(); + if (w) { + error = w->Wait(proc); + delete w; + } else + error = KErrNoMemory; + } else + proc.Resume(); + proc.Close(); + } + return error; + } + static int symbian_spawner(const char *command, TSpawnFlag aFlags) + { + TBuf<KMaxFileName> aFilename; + TBuf<KMaxFileName> aCommand; + TSpawnFlag aSpawnFlags = ESpawnWait; + CSpawnIoRedirect iord; + char *p = (char*)command; + + // The recognized syntax is: "cmd [args] [&]". Since one + // cannot pass more than (an argv[0] and) an argv[1] to a + // Symbian process anyway, not much is done to the cmd or + // the args, only backslash quoting. + + // Strip leading whitespace. + while (*p && isspace(*p)) p++; + if (*p) { + // Build argv[0]. + while (*p && !isspace(*p) && *p != '&') { + if (*p == '\\') { + if (p[1]) { + aFilename.Append(p[1]); + p++; + } + + } + else + aFilename.Append(*p); + p++; + } + + if (*p) { + // Skip whitespace between argv[0] and argv[1]. + while(*p && isspace(*p)) p++; + // Build argv[1]. + if (*p) { + char *a = p; + char *b = p + 1; + + while (*b) b++; + if (isspace(b[-1])) { + b--; + while (b > a && isspace(*b)) b--; + b++; + } + if (b > a && b[-1] == '&') { + // Parse backgrounding in any case, + // but turn it off only if wanted. + if ((aFlags & ESpawnWait)) + aSpawnFlags = + (TSpawnFlag) (aSpawnFlags & ~ESpawnWait); + b--; + if (isspace(b[-1])) { + b--; + while (b > a && isspace(*b)) b--; + b++; + } + } + for (p = a; p < b; p++) { + if (*p == '\\') { + if (p[1]) + aCommand.Append(p[1]); + p++; + } + else + aCommand.Append(*p); + } + } + // NOTE: I/O redirection is not yet done. + // Implementing that may require a separate server. + } + } + int spawned = symbian_spawn(aFilename, aCommand, aSpawnFlags, iord); + return spawned == KErrNone ? 0 : -1; + } + EXPORT_C int symbian_do_spawn(const char *command) + { + return symbian_spawner(command, ESpawnWait); + } + EXPORT_C int symbian_do_spawn_nowait(const char *command) + { + return symbian_spawner(command, ESpawnNone); + } + EXPORT_C int symbian_do_aspawn(void* vreally, void* vmark, void* sp) + { + return -1; + } +} + diff --git a/symbian/symbianish.h b/symbian/symbianish.h new file mode 100644 index 0000000000..1aebaf1007 --- /dev/null +++ b/symbian/symbianish.h @@ -0,0 +1,209 @@ +/* + * symbianish.h + * + * Copyright (c) Nokia 2004-2005. All rights reserved. + * This code is licensed under the same terms as Perl itself. + * + */ + +#include "symbian/symbian_port.h" + +/* + * The following symbols are defined if your operating system supports + * functions by that name. All Unixes I know of support them, thus they + * are not checked by the configuration script, but are directly defined + * here. + */ + +#ifndef PERL_MICRO + +/* HAS_IOCTL: + * This symbol, if defined, indicates that the ioctl() routine is + * available to set I/O characteristics + */ +#define HAS_IOCTL / **/ + +/* HAS_UTIME: + * This symbol, if defined, indicates that the routine utime() is + * available to update the access and modification times of files. + */ +/* #define HAS_UTIME / **/ + +/* HAS_GROUP + * This symbol, if defined, indicates that the getgrnam() and + * getgrgid() routines are available to get group entries. + * The getgrent() has a separate definition, HAS_GETGRENT. + */ +#undef HAS_GROUP /**/ + +/* HAS_PASSWD + * This symbol, if defined, indicates that the getpwnam() and + * getpwuid() routines are available to get password entries. + * The getpwent() has a separate definition, HAS_GETPWENT. + */ +#undef HAS_PASSWD /**/ + +#undef HAS_KILL +#undef HAS_WAIT + +#endif /* !PERL_MICRO */ + +/* USEMYBINMODE + * This symbol, if defined, indicates that the program should + * use the routine my_binmode(FILE *fp, char iotype) to insure + * that a file is in "binary" mode -- that is, that no translation + * of bytes occurs on read or write operations. + */ +#undef USEMYBINMODE + +/* Stat_t: + * This symbol holds the type used to declare buffers for information + * returned by stat(). It's usually just struct stat. It may be necessary + * to include <sys/stat.h> and <sys/types.h> to get any typedef'ed + * information. + */ +#define Stat_t struct stat + +/* USE_STAT_RDEV: + * This symbol is defined if this system has a stat structure declaring + * st_rdev + */ +#define USE_STAT_RDEV /**/ + +/* ACME_MESS: + * This symbol, if defined, indicates that error messages should be + * should be generated in a format that allows the use of the Acme + * GUI/editor's autofind feature. + */ +#undef ACME_MESS /**/ + +/* UNLINK_ALL_VERSIONS: + * This symbol, if defined, indicates that the program should arrange + * to remove all versions of a file if unlink() is called. This is + * probably only relevant for VMS. + */ +/* #define UNLINK_ALL_VERSIONS / **/ + +/* VMS: + * This symbol, if defined, indicates that the program is running under + * VMS. It is currently automatically set by cpps running under VMS, + * and is included here for completeness only. + */ +/* #define VMS / **/ + +/* ALTERNATE_SHEBANG: + * This symbol, if defined, contains a "magic" string which may be used + * as the first line of a Perl program designed to be executed directly + * by name, instead of the standard Unix #!. If ALTERNATE_SHEBANG + * begins with a character other then #, then Perl will only treat + * it as a command line if it finds the string "perl" in the first + * word; otherwise it's treated as the first line of code in the script. + * (IOW, Perl won't hand off to another interpreter via an alternate + * shebang sequence that might be legal Perl code.) + */ +/* #define ALTERNATE_SHEBANG "#!" / **/ + +#include <signal.h> +#define ABORT() abort() + +/* + * fwrite1() should be a routine with the same calling sequence as fwrite(), + * but which outputs all of the bytes requested as a single stream (unlike + * fwrite() itself, which on some systems outputs several distinct records + * if the number_of_items parameter is >1). + */ +#define fwrite1 fwrite + +#define Stat(fname,bufptr) stat((fname),(bufptr)) +#define Fstat(fd,bufptr) fstat((fd),(bufptr)) +#define Fflush(fp) fflush(fp) +#define Mkdir(path,mode) mkdir((path),(mode)) + +#ifndef PERL_SYS_TERM +#define PERL_SYS_TERM() OP_REFCNT_TERM; MALLOC_TERM; CloseSTDLIB(); +#endif + +#define BIT_BUCKET "NUL:" + +#define dXSUB_SYS + +#define NO_ENVIRON_ARRAY + +int kill(pid_t pid, int signo); +pid_t wait(int *status); + +#ifdef PERL_GLOBAL_STRUCT_PRIVATE +# undef PERL_GET_VARS +# undef PERL_SET_VARS +# undef PERL_UNSET_VARS +# define PERL_GET_VARS() symbian_get_vars() +# define PERL_SET_VARS(v) symbian_set_vars(v) +# define PERL_UNSET_VARS(v) symbian_unset_vars() +#endif /* #ifdef PERL_GLOBAL_STRUCT_PRIVATE */ + +#undef PERL_EXPORT_C +#define PERL_EXPORT_C EXPORT_C /* for perlio.h */ +#define PERL_CALLCONV EXPORT_C /* for prototype.h */ +#undef PERL_XS_EXPORT_C +#define PERL_XS_EXPORT_C EXPORT_C + +#ifndef PERL_CORE +#define PERL_CORE /* for WINS builds under VC */ +#endif + +#ifdef USE_PERLIO +#define PERL_NEED_APPCTX /* need storing the PerlBase* */ +#define PERLIO_STD_SPECIAL +#define PERLIO_STD_IN(f, b, n) symbian_read_stdin(f, b, n) +#define PERLIO_STD_OUT(f, b, n) symbian_write_stdout(f, b, n) +/* The console (the STD*) streams are seen by Perl in UTF-8. */ +#define PERL_SYMBIAN_CONSOLE_UTF8 + +#endif + +#undef Strerror +#undef strerror +#define Strerror(eno) ((eno) < 0 ? symbian_get_error_string(eno) : strerror(eno)) + +#define PERL_NEED_TIMESBASE + +#define times(b) symbian_times(b) +#define usleep(u) symbian_usleep(u) + +#define PERL_SYS_INIT(c, v) symbian_sys_init(c, v) + +#ifdef __SERIES60_1X__ +# error "Unfortunately Perl does not work in S60 1.2 (see FAQ-0929)" +#endif + +#ifdef _MSC_VER + +/* The Symbian SDK insists on the /W4 flag for Visual C. + * The Perl sources are not _that_ clean (Perl builds for Win32 use + * the /W3 flag, and gcc builds always use -Wall, so the sources are + * quite clean). To avoid a flood of warnings let's shut up most + * (for VC 6.0 SP 5). */ + +#pragma warning(disable: 4054) /* function pointer to data pointer */ +#pragma warning(disable: 4055) /* data pointer to function pointer */ +#pragma warning(disable: 4100) /* unreferenced formal parameter */ +#pragma warning(disable: 4101) /* unreferenced local variable */ +#pragma warning(disable: 4102) /* unreferenced label */ +#pragma warning(disable: 4113) /* prototype difference */ +#pragma warning(disable: 4127) /* conditional expression is constant */ +#pragma warning(disable: 4132) /* const object should be initialized */ +#pragma warning(disable: 4133) /* incompatible types */ +#pragma warning(disable: 4189) /* initialized but not referenced */ +#pragma warning(disable: 4244) /* conversion from ... possible loss ... */ +#pragma warning(disable: 4245) /* signed/unsigned char */ +#pragma warning(disable: 4310) /* cast truncates constant value */ +#pragma warning(disable: 4505) /* function has been removed */ +#pragma warning(disable: 4510) /* default constructor could not ... */ +#pragma warning(disable: 4610) /* struct ... can never be instantiated */ +#pragma warning(disable: 4701) /* used without having been initialized */ +#pragma warning(disable: 4702) /* unreachable code */ +#pragma warning(disable: 4706) /* assignment within conditional */ +#pragma warning(disable: 4761) /* integral size mismatch */ + +#endif /* _MSC_VER */ + diff --git a/symbian/uid.pl b/symbian/uid.pl new file mode 100644 index 0000000000..6eae8a9bcb --- /dev/null +++ b/symbian/uid.pl @@ -0,0 +1 @@ +0x102015F3 diff --git a/symbian/version.pl b/symbian/version.pl new file mode 100644 index 0000000000..c8bb82ebf7 --- /dev/null +++ b/symbian/version.pl @@ -0,0 +1,22 @@ +use strict; + +my %VERSION; + +if (open(PATCHLEVEL_H, "patchlevel.h")) { + while (<PATCHLEVEL_H>) { + if (/#define\s+PERL_(REVISION|VERSION|SUBVERSION)\s+(\d+)/) { + $VERSION{$1} = $2; + } + } + close PATCHLEVEL_H; +} else { + die "$0: patchlevel.h: $!\n"; +} + +die "$0: Perl release looks funny.\n" + unless (defined $VERSION{REVISION} && $VERSION{REVISION} == 5 && + defined $VERSION{VERSION} && $VERSION{VERSION} >= 8 && + defined $VERSION{SUBVERSION}); + + +\%VERSION; diff --git a/symbian/xsbuild.pl b/symbian/xsbuild.pl new file mode 100644 index 0000000000..ff743bda79 --- /dev/null +++ b/symbian/xsbuild.pl @@ -0,0 +1,861 @@ +#!/usr/bin/perl -w + +use strict; + +use Getopt::Long; +use File::Basename; +use Cwd; + +do "sanity.pl"; + +my $CoreBuild = -d "ext" && -f "perl.h" && -d "symbian" && -f "perl.c"; + +my $SymbianVersion = $ENV{XSBUILD_SYMBIAN_VERSION}; +my $PerlVersion = $ENV{XSBUILD_PERL_VERSION}; +my $CSuffix = '.c'; +my $CPlusPlus; +my $Config; +my $Build; +my $Clean; +my $DistClean; +my $Sis; + +sub usage { + die <<__EOF__; +$0: Usage: $0 [--symbian=version] [--perl=version] + [--csuffix=csuffix] [--cplusplus] + [--win=win] [--arm=arm] + [--config|--build|--clean|--distclean|--sis] ext +__EOF__ +} + +my $CWD; +my $SDK; +my $VERSION; +my $R_V_SV; +my $PERLSDK; +my $WIN; +my $ARM; +my $HOME = getcwd(); + +if ( !defined $PerlVersion && $0 =~ m:\\symbian\\perl\\(.+)\\bin\\xsbuild.pl:i ) +{ + $PerlVersion = $1; +} + +if ( !defined $SymbianVersion) { + ($SymbianVersion) = ($ENV{PATH} =~ m!C:\\Symbian\\(.+?)\\!i); +} + +my $S60SDK; + +if ($CoreBuild) { + unshift @INC, "symbian"; + do "sanity.pl"; + my %VERSION = %{ do "version.pl" }; + $SDK = do "sdk.pl"; + $VERSION = "$VERSION{REVISION}$VERSION{VERSION}$VERSION{SUBVERSION}"; + $R_V_SV = "$VERSION{REVISION}.$VERSION{VERSION}.$VERSION{SUBVERSION}"; + $HOME = do "cwd.pl"; + $SymbianVersion = $1 if $SDK =~ m:\\Symbian\\([^\\]+):; + $PerlVersion = $R_V_SV; + $S60SDK = $ENV{S60SDK}; # from sdk.pl +} + +usage() + unless GetOptions( + 'symbian=s' => \$SymbianVersion, + 'perl=s' => \$PerlVersion, + 'csuffix=s' => \$CSuffix, + 'cplusplus' => \$CPlusPlus, + 'win=s' => \$WIN, + 'arm=s' => \$ARM, + 'config' => \$Config, + 'build' => \$Build, + 'clean' => \$Clean, + 'distclean' => \$DistClean, + 'sis' => \$Sis + ); + +usage() unless @ARGV; + +$CSuffix = '.cpp' if $CPlusPlus; +$Build = !( $Config || $Clean || $DistClean ) || $Sis unless defined $Build; + +die "$0: Symbian version undefined\n" unless defined $SymbianVersion; + +$SymbianVersion =~ s:/:\\:g; + +die "$0: Symbian version '$SymbianVersion' not found\n" + unless -d "\\Symbian\\$SymbianVersion"; + +die "$0: Perl version undefined\n" unless defined $PerlVersion; + +die "$0: Perl version '$PerlVersion' not found\n" + if !$CoreBuild && !-d "\\Symbian\\Perl\\$PerlVersion"; + +print "Configuring with Symbian $SymbianVersion and Perl $PerlVersion...\n"; + +$SDK = "\\Symbian\\$SymbianVersion" unless defined $SDK; +$PERLSDK = "\\Symbian\\Perl\\$PerlVersion"; + +$R_V_SV = $PerlVersion; + +$VERSION =~ tr/.//d; + +$ENV{SDK} = $SDK; # For the Errno extension +$ENV{CROSS} = 1; # For the Encode extension + +my $UREL = $ENV{UREL}; # from sdk.pl +$UREL =~ s/-ARM-/$ARM/; +my $UARM = $ENV{UARM}; # from sdk.pl +my $SRCDBG = $UARM eq 'udeb' ? "SRCDBG" : ""; + +my %CONF; +my %EXTCFG; + +sub write_bld_inf { + my ($base) = @_; + print "\tbld.inf\n"; + open( BLD_INF, ">bld.inf" ) or die "$0: bld.inf: $!\n"; + print BLD_INF <<__EOF__; +PRJ_MMPFILES +$base.mmp +PRJ_PLATFORMS +$WIN $ARM +__EOF__ + close(BLD_INF); +} + +sub system_echo { + my $cmd = shift; + print "xsbuild: ", $cmd, "\n"; + return system($cmd); +} + +sub run_PL { + my ( $PL, $dir, $file ) = @_; + if ( defined $file ) { + print "\t(Running $dir\\$PL to create $file)\n"; + unlink($file); + } + else { + print "\t(Running $dir\\$PL)\n"; + } + my $cmd; + if ($CoreBuild) { + # Problem: the Config.pm we have in $HOME\\lib carries the + # version number of the Perl we are building, while the Perl + # we are running might have some other version. Solution: + # temporarily replace the Config.pm with a patched version. + my $V = sprintf "%vd", $^V; + unlink("$HOME\\lib\\Config.pm.bak"); + system_echo("perl -pi.bak -e \"s:\\Q$R_V_SV:$V:\" $HOME\\lib\\Config.pm"); + } + system_echo("perl -I$HOME\\lib -I$HOME\\xlib\\symbian $PL") == 0 + or warn "$0: $PL failed.\n"; + if ($CoreBuild) { + system_echo("copy $HOME\\lib\\Config.pm.bak $HOME\\lib\\Config.pm"); + } + if ( defined $file ) { -s $file or die "$0: No $file created.\n" } +} + +sub read_old_multi { + my ( $conf, $k ) = @_; + push @{ $conf->{$k} }, split( ' ', $1 ) if /^$k\s(.+)$/; +} + +sub uniquefy_filenames { + my $b = []; + my %c = (); + for my $i (@{$_[0]}) { + $i =~ s!/!\\!g; + $i = lc $i if $i =~ m!\\!; + $i =~ s!^c:!!; + push @$b, $i unless $c{$i}++; + } + return $b; +} + +sub read_mmp { + my ( $conf, $mmp ) = @_; + if ( -r $mmp && open( MMP, "<$mmp" ) ) { + print "\tReading $mmp...\n"; + while (<MMP>) { + chomp; + $conf->{TARGET} = $1 if /^TARGET\s+(.+)$/; + $conf->{TARGETPATH} = $1 if /^TARGETPATH\s+(.+)$/; + $conf->{EXTVERSION} = $1 if /^EXTVERSION\s+(.+)$/; + read_old_multi( $conf, "SOURCE" ); + read_old_multi( $conf, "SOURCEPATH" ); + read_old_multi( $conf, "USERINCLUDE" ); + read_old_multi( $conf, "SYSTEMINCLUDE" ); + read_old_multi( $conf, "LIBRARY" ); + read_old_multi( $conf, "MACRO" ); + } + close(MMP); + } +} + +sub write_mmp { + my ( $base, $userinclude, @src ) = @_; + + print "\t$base.mmp\n"; + $CONF{TARGET} = "$base.dll"; + $CONF{TARGETPATH} = "\\System\\Libs\\Perl\\$R_V_SV"; + $CONF{SOURCE} = [@src]; + $CONF{SOURCEPATH} = [ $CWD, $HOME ]; + $CONF{USERINCLUDE} = [ $CWD, $HOME ]; + $CONF{SYSTEMINCLUDE} = ["$PERLSDK\\include"] unless $CoreBuild; + $CONF{SYSTEMINCLUDE} = [ $HOME ] if $CoreBuild; + $CONF{LIBRARY} = []; + $CONF{MACRO} = []; + read_mmp( \%CONF, "_init.mmp" ); + read_mmp( \%CONF, "$base.mmp" ); + + for my $ui ( @{$userinclude} ) { + $ui =~ s!/!\\!g; + if ( $ui =~ m!^(?:[CD]:)?\\! ) { + push @{ $CONF{USERINCLUDE} }, $ui; + } + else { + push @{ $CONF{USERINCLUDE} }, "$HOME\\$ui"; + } + } + push @{ $CONF{SYSTEMINCLUDE} }, "\\epoc32\\include"; + push @{ $CONF{SYSTEMINCLUDE} }, "\\epoc32\\include\\libc"; + push @{ $CONF{LIBRARY} }, "euser.lib"; + push @{ $CONF{LIBRARY} }, "estlib.lib"; + push @{ $CONF{LIBRARY} }, "perl$VERSION.lib"; + push @{ $CONF{MACRO} }, "SYMBIAN" unless $CoreBuild; + push @{ $CONF{MACRO} }, "PERL_EXT" if $CoreBuild; + push @{ $CONF{MACRO} }, "MULTIPLICITY"; + push @{ $CONF{MACRO} }, "PERL_IMPLICIT_CONTEXT"; + push @{ $CONF{MACRO} }, "PERL_GLOBAL_STRUCT"; + push @{ $CONF{MACRO} }, "PERL_GLOBAL_STRUCT_PRIVATE"; + + for my $u (qw(SOURCE SOURCEPATH SYSTEMINCLUDE USERINCLUDE LIBRARY MACRO)) { + $CONF{$u} = uniquefy_filenames( $CONF{$u} ); + } + open( BASE_MMP, ">$base.mmp" ) or die "$0: $base.mmp: $!\n"; + + print BASE_MMP <<__EOF__; +TARGET $CONF{TARGET} +TARGETTYPE dll +TARGETPATH $CONF{TARGETPATH} +SOURCE @{$CONF{SOURCE}} +$SRCDBG +__EOF__ + for my $u (qw(SOURCEPATH SYSTEMINCLUDE USERINCLUDE)) { + for my $v ( @{ $CONF{$u} } ) { + print BASE_MMP "$u\t$v\n"; + } + } + # OPTION does not work in MMPs for pre-2.0 SDKs? + print BASE_MMP <<__EOF__; +LIBRARY @{$CONF{LIBRARY}} +MACRO @{$CONF{MACRO}} +// OPTION MSVC /P +// OPTION GCC -E +__EOF__ + close(BASE_MMP); + +} + +sub write_makefile { + my ( $base, $build ) = @_; + + print "\tMakefile\n"; + + my $windef1 = "$SDK\\Epoc32\\Build$CWD\\$base\\$WIN\\$base.def"; + my $windef2 = "..\\BWINS\\${base}u.def"; + my $armdef1 = "$SDK\\Epoc32\\Build$CWD\\$base\\$ARM\\$base.def"; + my $armdef2 = "..\\BMARM\\${base}u.def"; + + my $wrap = $SDK && $S60SDK eq '1.2' && $SDK !~ /_CW$/; + my $ABLD = $wrap ? 'perl b.pl' : 'abld'; + + open( MAKEFILE, ">Makefile" ) or die "$0: Makefile: $!\n"; + print MAKEFILE <<__EOF__; +WIN = $WIN +ARM = $ARM +ABLD = $ABLD + +all: build freeze + +sis: build_arm freeze_arm + +build: abld.bat build_win build_arm + +abld.bat: + bldmake bldfiles + +build_win: abld.bat + bldmake bldfiles + \$(ABLD) build \$(WIN) udeb + +build_arm: abld.bat + bldmake bldfiles + \$(ABLD) build \$(ARM) $UARM + +win: build_win freeze_win + +arm: build_arm freeze_arm + +freeze: freeze_win freeze_arm + +freeze_win: + bldmake bldfiles + \$(ABLD) freeze \$(WIN) $base + +freeze_arm: + bldmake bldfiles + \$(ABLD) freeze \$(ARM) $base + +defrost: defrost_win defrost_arm + +defrost_win: + -del /f $windef1 + -del /f $windef2 + +defrost_arm: + -del /f $armdef1 + -del /f $armdef2 + +clean: clean_win clean_arm + +clean_win: + \$(ABLD) clean \$(WIN) + +clean_arm: + \$(ABLD) clean \$(ARM) + +realclean: clean realclean_win realclean_arm + -del /f _init.c b.pl + -del /f $base.c $base.mmp + +realclean_win: + \$(ABLD) reallyclean \$(WIN) + +realclean_arm: + \$(ABLD) reallyclean \$(ARM) + +distclean: defrost realclean + -rmdir ..\\BWINS ..\\BMARM + -del /f const-c.inc const-xs.inc + -del /f Makefile abld.bat bld.inf +__EOF__ + close(MAKEFILE); + if ($wrap) { + if(open(B,">b.pl")) { + print B <<'__EOF__'; +# abld.pl wrapper. + +# nmake doesn't like MFLAGS and MAKEFLAGS being set to -w and w. +delete $ENV{MFLAGS}; +delete $ENV{MAKEFLAGS}; + +print "abld @ARGV\n"; +system("abld @ARGV"); +__EOF__ + close(B); + } else { + warn "$0: failed to create b.pl: $!\n"; + } + } +} + +sub update_dir { + print "[chdir from ", getcwd(), " to "; + chdir(shift) or return; + update_cwd(); + print getcwd(), "]\n"; +} + +sub xsconfig { + my ( $ext, $dir ) = @_; + print "Configuring for $ext, directory $dir...\n"; + my $extu = $CoreBuild ? "$HOME\\lib\\ExtUtils" : "$PERLSDK\\lib\\ExtUtils"; + update_dir($dir) or die "$0: chdir '$dir': $!\n"; + my $build = dirname($ext); + my $base = basename($ext); + my $basexs = "$base.xs"; + my $basepm = "$base.pm"; + my $basec = "$base$CSuffix"; + my $extdir = "."; + if ( $dir =~ m:^ext\\(.+): ) { + $extdir = $1; + } + elsif ( $dir ne "." ) { + $extdir = $dir; + } + my $extdirdir = dirname($extdir); + my $targetroot = "\\System\\Libs\\Perl\\$R_V_SV"; + write_bld_inf($base) if -f $basexs; + + my %src; + $src{$basec}++; + + $extdirdir = $extdirdir eq "." ? "" : "$extdirdir\\"; + + my %lst; + $lst{"$UREL\\$base.dll"} = + "$targetroot\\$ARM-symbian\\$base.dll" + if -f $basexs; + $lst{"$dir\\$base.pm"} = "$targetroot\\$extdirdir$base.pm" + if -f $basepm && $base ne 'XSLoader'; + + my %incdir; + my $ran_PL; + if ( -d 'lib' ) { + use File::Find; + my @found; + find( sub { push @found, $File::Find::name if -f $_ }, 'lib' ); + for my $found (@found) { + my ($short) = ( $found =~ m/^lib.(.+)/ ); + $short =~ s!/!\\!g; + $found =~ s!/!\\!g; + $lst{"$dir\\$found"} = "$targetroot\\$short"; + } + } + if ( my @pm = glob("*.pm */*.pm") ) { + for my $pm (@pm) { + next if $pm =~ m:^t/:; + $pm =~ s:/:\\:g; + $lst{"$dir\\$pm"} = "$targetroot\\$extdirdir$pm"; + } + } + if ( my @c = glob("*.c *.cpp */*.c */*.cpp") ) { + for my $c (@c) { + $c =~ s:/:\\:g; + $src{$c}++; + } + } + if ( my @h = glob("*.h */*.h") ) { + for my $h (@h) { + $h =~ s:/:\\:g; + $h = dirname($h); + $incdir{"$dir\\$h"}++ unless $h eq "."; + } + } + if ( exists $EXTCFG{$ext} ) { + for my $cfg ( @{ $EXTCFG{$ext} } ) { + if ( $cfg =~ /^([-+])?(.+\.(c|cpp|h))$/ ) { + my $o = defined $1 ? $1 : '+'; + my $f = $2; + $f =~ s:/:\\:g; + for my $f ( glob($f) ) { + if ( $o eq '+' ) { + warn "$0: no source file $dir\\$f\n" unless -f $f; + $src{$f}++ unless $cfg =~ /\.h$/; + if ( $f =~ m:^(.+)\\[^\\]+$: ) { + $incdir{$1}++; + } + } + elsif ( $o eq '-' ) { + delete $src{$f}; + } + } + } + if ( $cfg =~ /^([-+])?(.+\.(pm|pl|inc))$/ ) { + my $o = defined $1 ? $1 : '+'; + my $f = $2; + $f =~ s:/:\\:g; + for my $f ( glob($f) ) { + if ( $o eq '+' ) { + warn "$0: no Perl file $dir\\$f\n" unless -f $f; + $lst{"$dir\\$f"} = "$targetroot\\$extdir\\$f"; + } + elsif ( $o eq '-' ) { + delete $lst{"$dir\\$f"}; + } + } + } + if ( $cfg eq 'CONST' && !$ran_PL++ ) { + run_PL( "Makefile.PL", $dir, "const-xs.inc" ); + } + } + } + unless ( $ran_PL++ ) { + run_PL( "Makefile.PL", $dir ) if -f "Makefile.PL"; + } + if ( $dir eq "ext\\Errno" ) { + run_PL( "Errno_pm.PL", $dir, "Errno.pm" ); + $lst{"$dir\\Errno.pm"} = "$targetroot\\Errno.pm"; + } + elsif ( $dir eq "ext\\Devel\\PPPort" ) { + run_PL( "ppport_h.PL", $dir, "ppport.h" ); + } + elsif ( $dir eq "ext\\DynaLoader" ) { + run_PL( "XSLoader_pm.PL", $dir, "XSLoader.pm" ); + $lst{"ext\\DynaLoader\\XSLoader.pm"} = "$targetroot\\XSLoader.pm"; + } + elsif ( $dir eq "ext\\Encode" ) { + system_echo("perl bin\\enc2xs -Q -O -o def_t.c -f def_t.fnm") == 0 + or die "$0: running enc2xs failed: $!\n"; + } + + my @lst = sort keys %lst; + + read_mmp( \%CONF, "_init.mmp" ); + read_mmp( \%CONF, "$base.mmp" ); + + if ( -f $basexs ) { + my %MM; # MakeMaker results + my @MM = qw(VERSION XS_VERSION); + if ( -f "Makefile" ) { + print "\tReading MakeMaker Makefile...\n"; + if ( open( MAKEFILE, "Makefile" ) ) { + while (<MAKEFILE>) { + for my $m (@MM) { + if (m!^$m = (.+)!) { + $MM{$m} = $1; + print "\t$m = $1\n"; + } + } + } + close(MAKEFILE); + } + else { + warn "$0: Makefile: $!"; + } + print "\tDeleting MakeMaker Makefile.\n"; + unlink("Makefile"); + } + + unlink($basec); + print "\t$basec\n"; + if ( defined $CONF{EXTVERSION} ) { + my $EXTVERSION = $CONF{EXTVERSION}; + print "\tUsing $EXTVERSION for version...\n"; + $MM{VERSION} = $MM{XS_VERSION} = $EXTVERSION; + } + die "VERSION or XS_VERSION undefined\n" + unless defined $MM{VERSION} && defined $MM{XS_VERSION}; + if ( open( BASE_C, ">$basec" ) ) { + print BASE_C <<__EOF__; +#ifndef VERSION +#define VERSION "$MM{VERSION}" +#endif +#ifndef XS_VERSION +#define XS_VERSION "$MM{XS_VERSION}" +#endif +__EOF__ + close(BASE_C); + } + else { + warn "$0: $basec: $!"; + } + unless ( + system( +"perl -I$PERLSDK\\lib $extu\\xsubpp -C++ -csuffix .cpp -typemap $extu\\typemap -noprototypes $basexs >> $basec" + ) == 0 + && -s $basec + ) + { + die "$0: perl xsubpp failed: $!\n"; + } + + print "\t_init.c\n"; + open( _INIT_C, ">_init.c" ) or die "$!: _init.c: $!\n"; + print _INIT_C <<__EOF__; + #include "EXTERN.h" + #include "perl.h" + EXPORT_C void _init(void *handle) { + } +__EOF__ + close(_INIT_C); + + my @src = ( "_init.c", sort keys %src ); + + if ( $base eq "Encode" ) { # Currently unused. + for my $submf ( glob("*/Makefile") ) { + my $d = dirname($submf); + print "Configuring Encode::$d...\n"; + if ( open( SUBMF, $submf ) ) { + if ( update_dir($d) ) { + my @subsrc; + while (<SUBMF>) { + next if 1 .. /postamble/; + if (m!^(\w+_t)\.c : !) { + system( + "perl ..\\bin\\enc2xs -Q -o $1.c -f $1.fnm") + == 0 + or warn "$0: enc2xs: $!\n"; + push @subsrc, "$1.c"; + } + } + close(SUBMF); + unlink($submf); + my $subbase = $d; + $subbase =~ s!/!::!g; + write_mmp( $subbase, ["..\\Encode"], "$subbase.c", + @subsrc ); + write_makefile( $subbase, $build ); + write_bld_inf($subbase); + + unless ( + system( +"perl -I$HOME\\lib ..\\$extu\\xsubpp -C++ -csuffix .cpp -typemap ..\\$extu\\typemap -noprototypes $subbase.xs > $subbase.c" + ) == 0 + && -s "$subbase.c" + ) + { + die "$0: perl xsubpp failed: $!\n"; + } + update_dir(".."); + } + else { + warn "$0: chdir $d: $!\n"; + } + } + else { + warn "$0: $submf: $!"; + } + } + print "Configuring Encode...\n"; + } + + write_mmp( $base, [ keys %incdir ], @src ); + write_makefile( $base, $build ); + } + my $lstname = $ext; + $lstname =~ s:^ext\\::; + $lstname =~ s:\\:-:g; + print "\t$lstname.lst\n"; + my $lstout = + $CoreBuild ? "$HOME/symbian/$lstname.lst" : "$HOME/$lstname.lst"; + if ( open( my $lst, ">$lstout" ) ) { + for my $f (@lst) { print $lst qq["$f"-"!:$lst{$f}"\n] } + close($lst); + } + else { + die "$0: $lstout: $!\n"; + } + update_dir($HOME); +} + +sub update_cwd { + $CWD = getcwd(); + $CWD =~ s!^[CD]:!!i; + $CWD =~ s!/!\\!g; +} + +for my $ext (@ARGV) { + + $ext =~ s!::!\\!g; + $ext =~ s!/!\\!g; + + my $cfg; + + $cfg = $2 if $ext =~ s/(.+?),(.+)/$1/; + + my $dir; + + unless ( -e $ext ) { + if ( $ext =~ /\.xs$/ && !-f $ext ) { + if ( -f "ext\\$ext" ) { + $ext = "ext\\$ext"; + $dir = dirname($ext); + } + } + elsif ( !-d $ext ) { + if ( -d "ext\\$ext" ) { + $ext = "ext\\$ext"; + $dir = $ext; + } + } + $dir = "." unless defined $dir; + } + else { + if ( $ext =~ /\.xs$/ && -f $ext ) { + $ext = dirname($ext); + $dir = $ext; + } + elsif ( -d $ext ) { + $dir = $ext; + } + } + + if ( $ext eq "XSLoader" ) { + $ext = "ext\\XSLoader"; + } + if ( $ext eq "ext\\XSLoader" ) { + $dir = "ext\\DynaLoader"; + } + + $EXTCFG{$ext} = [ split( /,/, $cfg ) ] if defined $cfg; + + die "$0: no lib\\Config.pm\n" + if $CoreBuild && $Build && !-f "lib\\Config.pm"; + + if ($CoreBuild) { + open( my $cfg, "symbian/install.cfg" ) + or die "$0: symbian/install.cfg: $!\n"; + my $extdir = $dir; + $extdir =~ s:^ext\\::; + while (<$cfg>) { + next unless /^ext\s+(.+)/; + chomp; + my $ext = $1; + my @ext = split( ' ', $ext ); + $EXTCFG{"ext\\$ext[0]"} = [@ext]; + } + close($cfg); + } + + if ( $Config || $Build ) { + xsconfig( $ext, $dir ) or die "$0: xsconfig '$ext' failed\n"; + next if $Config; + } + + my $chdir = $ext eq "ext\\XSLoader" ? "ext\\DynaLoader" : $dir; + die "$0: no directory '$chdir'\n" unless -d $chdir; + update_dir($chdir) or die "$0: chdir '$chdir' failed: $!\n"; + + my %CONF; + + my @ext = split( /\\/, $ext ); + my $base = $ext[-1]; + + if ( $Clean || $DistClean ) { + print "Cleaning $ext...\n"; + unlink("bld.inf"); + unlink("$base.mmp"); + unlink("_init.c"); + unlink("const-c.inc"); + unlink("const-xs.inc"); + rmdir("..\\bmarm"); + } + + if ( $Build && $ext ne "ext\\XSLoader" && $ext ne "ext\\Errno" ) { + + # We compile the extension three (3) times. + # (1) Only the _init.c to get _init() as the ordinal 1 function in the DLL. + # (2) With the rest and the _init.c to get ordinals for the rest. + # (3) With an updated _init.c that carries the symbols from step (2). + + system("make clean"); + system("make defrost") == 0 or die "$0: make defrost failed\n"; + + my @TARGET; + + push @TARGET, 'sis' if $Sis; + + # Compile #1. + # Hide all but the _init.c. + print "\n*** $ext - Compile 1 of 3.\n\n"; + system( +"perl -pi.bak -e \"s:^SOURCE\\s+_init.c:SOURCE\\t_init.c // :\" $base.mmp" + ); + system("bldmake bldfiles"); + system("make @TARGET") == 0 or die "$0: make #1 failed\n"; + + # Compile #2. + # Reveal the rest again. + print "\n*** $ext - Compile 2 of 3.\n\n"; + system( +"perl -pi.bak -e \"s:^SOURCE\\t_init.c // :SOURCE\\t_init.c :\" $base.mmp" + ); + system("make @TARGET") == 0 or die "$0: make #2 failed\n"; + unlink("$base.mmp.bak"); + + open( _INIT_C, ">_init.c" ) or die "$0: _init.c: $!\n"; + print _INIT_C <<'__EOF__'; +#include "EXTERN.h" +#include "perl.h" + +/* This is a different but matching definition from in dl_symbian.xs. */ +typedef struct { + void* handle; + int error; + HV* symbols; +} PerlSymbianLibHandle; + +EXPORT_C void _init(void* handle) { +__EOF__ + + my %symbol; + my $def; + my $basef; + for my $f ("$SDK\\Epoc32\\Build$CWD\\$base\\WINS\\$base.def", + "..\\BMARM\\${base}u.def") { + print "\t($f - "; + if ( open( $def, $f ) ) { + print "OK)\n"; + $basef = $f; + last; + } else { + print "no)\n"; + } + } + unless (defined $basef) { + die "$0: failed to find .def for $base\n"; + } + while (<$def>) { + next while 1 .. /^EXPORTS/; + if (/^\s*(\w+) \@ (\d+) /) { + $symbol{$1} = $2; + } + } + close($def); + + my @symbol = sort keys %symbol; + if (@symbol) { + print _INIT_C <<'__EOF__'; + dTHX; + PerlSymbianLibHandle* h = (PerlSymbianLibHandle*)handle; + if (!h->symbols) + h->symbols = newHV(); + if (h->symbols) { +__EOF__ + for my $sym (@symbol) { + my $len = length($sym); + print _INIT_C <<__EOF__; + hv_store(h->symbols, "$sym", $len, newSViv($symbol{$sym}), 0); +__EOF__ + } + } + else { + die "$0: $basef: no exports found\n"; + } + + print _INIT_C <<'__EOF__'; + } +} +__EOF__ + close(_INIT_C); + + # Compile #3. This is for real. + print "\n*** $ext - Compile 3 of 3.\n\n"; + system("make @TARGET") == 0 or die "$0: make #3 failed\n"; + + } + elsif ( $Clean || $DistClean ) { + if ( $ext eq "ext\\Errno" ) { + unlink( "Errno.pm", "Makefile" ); + } + else { + if ( -f "Makefile" ) { + if ($Clean) { + system("make clean") == 0 or die "$0: make clean failed\n"; + } + elsif ($DistClean) { + system("make distclean") == 0 + or die "$0: make distclean failed\n"; + } + } + if ( $ext eq "ext\\Devel\\PPPort" ) { + unlink("ppport.h"); + } + } + my @B = glob("ext/BWINS ext/BMARM ext/*/BWINS ext/*/BMARM Makefile"); + rmdir(@B) if @B; + } + + update_dir($HOME); + +} # for my $ext + +exit(0); + |