Skip to content
Zwetan Kjukov edited this page Feb 2, 2016 · 2 revisions

Directly born from redtamarin, as3shebang is a single executable that self contain all the goodness with much less hassle.

Ever been tempted to toy with redtamarin but didn't have the time to investigate more than that ?

as3shebang is here to solve that exact problem: one installer, one little rule to follow and nothing else should stop you ;).

Clarifications of Stuff

Here a list of few quick facts and stuff about all that technology.

  • AVM2 is the ActionScript Virtual Machine 2.0
  • AVM2 is what interpret ActionScript Bytecode (ABC)
    inside the Flash player and the AIR runtime
  • you create ABC files by compiling ActionScript 3.0 source code
  • Tamarin is the open source AVM2,
    you can find it here: avmplus
  • Tamarin does not contain the sources
    of the Flash or AIR API (no UI, no sound, no image, etc.)
  • Redtamarin is an open source project
  • Redtamarin extends Tamarin with native code (C++)
    for Windows, Mac OS X and Linux in 32-bit and 64-bit
  • Redtamarin provides a POSIX / C API
    (stdlib, stdio, unistd, socket, etc.)
  • Redtamarin provides native classes
    (Program, Runtime, OperatingSystem, etc.)
  • Redtamarin provides implementations of the Flash and AIR API
    (ByteArray, Proxy, Workers, etc.)
  • Redtamarin produces shell executable: redshell
  • Redshell can execute ABC, AS and SWF files
  • a SWF file is a container of multiple ABC files
  • you can merge the redshell with an ABC file
    to produce a single independent executable
  • the Redtamarin API allow you to eval AS3 source code at runtime

Introduction

As a developer, especially in open source, I have always been bothered by the barrier to entry that some projects impose right from the start, which sadly could discourage most people who just want to try something new without all the hurdle of building the thing from scratch.

Sure you can take the sources and build Redtamarin yourself, this is hard;
a bit easier is to download the Redtamarin SDK and install/configure the different environment variables, executables, etc., this is still complicated.

Even me, who know all that stuff from the inside out, I needed something simple, fast to install and easy to use right away.

I give you as3shebang :).

ATTENTION
from v0.9 to v1.0 things have changed a little
now as3shebang works for Windows, Mac OS X and Linux
see the install instructions in the README

As a Linux sysadmin now I can do that

$ wget https://github.com/Corsaair/as3shebang/releases/download/v0.9-1/as3shebang_0.9-1_amd64.deb
$ dpkg -i as3shebang_0.9-1_amd64.deb

What is as3shebang ?

Simply put, as3shebang is an ActionScript 3.0 source code of a dozen lines that is compiled
as3shebang.as -> as3shebang.abc
and embedded within the Redtamarin shell: redshell
redshell_dd + as3shebang.abc = as3shebang

It's only purpose is to be called by your shell environment by the way of the shebang line.

#!/usr/bin/as3shebang

It's a hack, here the details

A series of small hacks that work well together :p

  1. a redtamarin executable need to use a special kind of arguments
    myprogram a b c would configure the redshell executable itself,
    to configure your program you need to use --, and so if you want to
    pass a, b, c as arguments to myprogram you need to do myprogram -- a b c
    that's why you need to write the shebang line like this #!/usr/bin/as3shebang --
    and not like that #!/usr/bin/as3shebang.

ATTENTION
from v0.9 to v1.0 things have changed a little
you don't need to use -- anymore

  1. While executing a program with redshell you need to use --
    to pass arguments to your program, it is not needed anymore with
    the new projectors (standalone executable) used by as3shebang 1.0.0
    now you can directly call myprogram a b c and it will work, so
    the shebang line now is just #!/usr/bin/as3shebang.

  2. ActionScript 3.0 source code do not support comments line starting with #
    the classic shebang line #!/something will make the ActionScript compiler or interpreter
    throw an error and block the whole flow of the program.

  3. as3shebang simply cut off the shebang line
    we don't read it, we don't really care about it
    it's only purpose is to use the shell mechanism
    to put us inside the redshell at runtime.

  4. Redtamarin can evalute ActionScript 3.0 source code at runtime
    yes you read that right, we do have an eval() function
    and this is exactly what as3shebang is using to "run" the script.

Bugs and Glitches

Because the scripts are evaluated at runtime you may encounter some glitches with imported classes or packages not recognised by the environment.

For example

#!/usr/bin/as3shebang

import C.errno.*;

var err:CError = new CError( "", 13 );
trace( err );

when you execute it $ ./test you will get

VerifyError: Error #1014: Class CError could not be found.
	at shell::Runtime$/eval()
	at global$init()

a simple workaround is to use the any type * for the variable

#!/usr/bin/as3shebang

import C.errno.*;

var err:* = new CError( "", 13 );
trace( err );

and now $ ./test output correctly

CError: EACCES #13: Permission denied

Also, AS3 shell scripts containing the shebang line are incompatible to run with the redshell or to be compiled with ASC (ActionScript Compiler).

If the script above is named test, then running
$ ./redshell test
will simply fail with the following error

SyntaxError: test:1: Syntax error: Illegal character in input: #

or compiling
$ java -jar asc.jar -AS3 -import redtamarin.abc test
will output numerous compiler errors

[Compiler] Error #1093: Syntax error.
   sample2, Ln 1, Col 1: 
   #!/usr/bin/as3shebang
   ^

[Compiler] Error #1093: Syntax error.
   sample2, Ln 1, Col 3: 
   #!/usr/bin/as3shebang
   ..^

[Compiler] Error #1084: Syntax error: expecting identifier before in.
   sample2, Ln 1, Col 9: 
   #!/usr/bin/as3shebang
   ........^

[Compiler] Error #1093: Syntax error.
   sample2, Ln 1, Col 11: 
   #!/usr/bin/as3shebang
   ..........^

4 errors found

Features

  1. You can execute ActionScript 3.0 shell scripts
  2. Support all the AS3 builtins and the Redtamarin API
    see the documentation: https://docs.redtamarin.com/latest/
  3. full error stacktrace
  4. You can pass arguments to those AS3 shell scripts
  5. You can pipe string and binary
  6. You can run them as CGI scripts under Apache

as3shebang is compiled with the redshell debug debugger, if your shell script contain errors you will obtain a stacktrace

Example

#!/usr/bin/as3shebang

trace( "UNKNOWN = " + UNKNOWN );

when executed will output

ReferenceError: Error #1065: Variable UNKNOWN is not defined.
	at global$init()[:2]
	at shell::Runtime$/eval()
	at global$init()

Example to pass arguments

#!/usr/bin/as3shebang

import shell.Program;

for( var i:uint = 0; i < Program.argv.length; i++ )
{
	trace( "argv[" + i + "] = " + Program.argv[i] );
}

execute $ ./test a b c and you will get

argv[0] = a
argv[1] = b
argv[2] = c

Attention, there are some subtle differenced compared to executing a script with redshell.

In Redtamarin, you can get arguments using Program.argv or C.argv and C.argc, and by default C.argv[0] contains the name of your executed script (eg. Program.filename).

ATTENTION
from v0.9 to v1.0 things have changed a little
we do some magic to the arguments :)

But with as3shebang, an AS3 shell script will read the first argument from Program.argv[0].

While as3shebang is read, we read the first argument Program.argv[0] to find the shell script.

If you try to find the name of the executable with Program.filename
you will obtain "/usr/bin/as3shebang" (the resolved path to the as3shebang executable).

When as3shebang interpret your shell script, if you try to find the name of the executable
with Program.filename you will obtain the name of the shell script "./test" (for example).

To obtain your AS3 shell script executable name
you will need to use a magic variable named scriptname.

To obtain your AS3 shell script executable name
either use Program.filename or C.argv[0].

For example

#!/usr/bin/as3shebang

import shell.*;
trace( "scriptname = " + Program.filename );

if you ran the command $ ./test you will then obtain

scriptname = ./test

Another magic variable is as3shebang
which contains the version of the as3shebang executable

#!/usr/bin/as3shebang

trace( "as3shebang " + as3shebang );

this does not work anymore with v1.0.0

Instead, now you can detect if your program
is running as a shell script using Program.type

#!/usr/bin/as3shebang

import shell.*;

if( Program.type == ShellType.SCRIPT )
{
    trace( "I'm a shell script" );
}

So, earlier I mentioned you can pipe string and binary, here how to do that.

$ touch sample1
$ chmod + sample1
$ nano sample1

#!/usr/bin/as3shebang

import C.stdio.*;
import flash.utils.ByteArray;


var bytes:* = new ByteArray();
var read:int = fread( bytes, 1024, stdin );

trace( "read " + read + " bytes" );

bytes.position = 0;
var flat:String = bytes.readUTFBytes( bytes.length );
trace( "----" );
trace( flat );
trace( "----" );

let's pipe into our program
$ cat sample1 | ./sample1

will output the following

read 314 bytes
----
#!/usr/bin/as3shebang

import C.stdio.*;
import flash.utils.ByteArray;


var bytes:* = new ByteArray();
var read:int = fread( bytes, 1024, stdin );

trace( "read " + read + " bytes" );

bytes.position = 0;
var flat:String = bytes.readUTFBytes( bytes.length );
trace( "----" );
trace( flat );
trace( "----" );
----

With stdio function you can read and write to/from stdin, stdout, stderr etc. using a ByteArray that will supports manipulating binaries and strings.

ATTENTION
from v0.9 to v1.0 things have changed a little
under Windows you will need to set the console
mode to binary with C.conio.set_binary_mode()

example

     // if under Windows we set our console to binary
     if( Runtime.platform == "windows" )
     {
         set_binary_mode( STDIN_FILENO, true );
     }

to pipe a binary as input
$ cat image.png | ./yourprogram
just fread() the stdin.

to pipe a binary as output
$ ./yourprogram | xxd (xxd for a nice hexdump)
just fwrite() to stdout.

You will find a fullblown example in the Redtamarin API documentation under C.conio.set_binary_mode().

And last but not least, here how to run your AS3 shell scripts as CGI scripts under Apache.

Let's define a basic apache conf

<VirtualHost *:80>
    ServerName www.foobar.com
    
    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/foobar-error.log
    CustomLog ${APACHE_LOG_DIR}/foobar-access.log vhost_combined

    DocumentRoot /var/www/foobar/htdocs

    <Directory />
      Options FollowSymLinks
      AllowOverride All
    </Directory>

    <Directory "/var/www/foobar/htdocs/">
      Options Indexes FollowSymLinks MultiViews Includes
      AllowOverride All
      Require all granted
      Options +ExecCGI

      <FilesMatch (.*)$>
        SetHandler cgi-script
      </FilesMatch>

    </Directory>

</VirtualHost>

now in your htdocs directory create your shell script
$ touch index
$ chmod +x index
$nano index

#!/usr/bin/as3shebang

trace( "Content-Type: text/plain; charset=utf-8" );
trace( "" );
trace( "hello world" );

access https://www.foobar.com/index from a browser
and you should get this

hello world