/********************************************************
 * Turbo Tentacle v1.2                                  *
 * Written by DeusXmachina <deusxmachina@webmail.co.za> *
 * Re-implementation of Tentakel-Coder in C             *
 * by Christian Garbs <mitch@cgarbs.de>                 *
 * Faster by a factor of 20+ under BSD license ;-)      *
 *                                                      *
 * CHANGES:                                             *
 *   2001-09-30: Some cleanup, re-implementation of     *
 *               randtentacle, now using better RNG     *
 *   2001-09-27: v1.1 Bugfix based on posting by        *
 *               Robert Lange <robert.lange@gmx.net>    *
 *   2001-09-26: Release of v1.0                        *
 ********************************************************/

#include <stdio.h>
#include <stdlib.h>

unsigned char randtentacle( void )
{
   static unsigned char tentaclechar[] = "_~-=";
   static long k;
   static long a     = 16807;
   static long m     = 2147483647;
   static long q     = 127773;
   static long r     = 2836;
   static long akku  = 42;
   static double div = 4.0 / 2147483647;

   k    = akku / q;
   akku = a * (akku - k*q) - r*k;
   if (akku < 0)
   {
     akku += m;
   }
   return tentaclechar[(int) (akku * div)];
}

int char2int( unsigned char value )
{
   switch (value)
   {
      case '_': return 11;
      case '~': return  7;
      case '-': return  3;
      case '=': return  1;
   }
   return 0;
}

/****************************************************************
 * I had some trouble to make this work for binary files        *
 ****************************************************************/

void encode( FILE *file )
{
   unsigned char value;
   unsigned char head   = 'o';
   unsigned char foot   = ')';
   unsigned char segment;
   int  equiv;

   while ( 1 )
   {
      value = getc( file );
      if (feof( file ))
      {
         break;
      }
      printf( "%c",   foot );
      while (value != 0)
      {
         segment = randtentacle( );
         equiv   = char2int( segment );
         if (equiv <= value)
         {
            value -= equiv;
            printf( "%c", segment );
         }
      }
      printf( "%c\n", head );
   }
}

/********************************************************
 * This implementation of decode works even if tentacle * 
 * file uses follows MAC line end encoding convention.  *
 ********************************************************/

void decode( FILE *file )
{
   unsigned char value;
   int  sum    = 0;
   int  ignore = 0;

   while ( !feof( file ))
   {
      value = getc( file );
      if ( !ignore && (value == '\n' || value == '\r'))
      {
         printf( "%c", sum );
         sum = 0;
         ignore = 1;
      }
      else
      {
         sum += char2int( value );
         ignore = 0;
      }
   }
}

int main( int argc, unsigned char * argv[] )
{
   unsigned char action;
   FILE* file;

   if (argc < 2 || strlen( argv[1]) != 2 || argv[1][0] != '-'
                || (argv[1][1] != 'd' && argv[1][1] != 'e') )
   {
      printf( "%s%s%s%s%s%s%s",
              "Turbo tentacle v0.1",
              "(C) 2001 by DeusXmachina <deusxmachina@webmail.co.za>\n",
              "Usage: ",
              *argv,
              " (-d|-e) [file1] [file2] [...]\n",
              "\toption -d:  decode\n",
              "\toption -e:  encode\n" );
      return 1;
   }
   
   action = argv[1][1];

   if (argc == 2)
   {
      if ( action == 'e')
      {
         encode( stdin );
      }
      else
      {
         decode( stdin );
      }
   }
   else
   {
     argv++;
  
     while (*(++argv) != NULL)
     {
        if ( (file = fopen( *argv, "rb" )) == NULL)
        {
           fprintf( stderr, "File %s does not exist. Terminating.\n", *argv );
           return 1;
        }
        else
        {
           if ( action == 'e')
           {
              encode( file );
           }
           else
           {
              decode( file );
           }
           fclose ( file );
        }
     }
   }
   return 0;
}
