tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
/*
// This file is a part of the TMI distribution mudlib.
// Please retain this header if you use this code.
// Devised & Written by Douglas Reay (Pallando @ TMI, Ephemeral Dale, etc)
// Moved to TMI-II (25-11-92)
*/
#include <disclaimer.h>

#include <mudlib.h>

inherit DAEMON;

#define LIMIT 20
#define TAB "	"

int waste_ch( string a );
void compress_lines( mixed a );
void resave_file( mixed new_lines, string file_name, object player );
string help();

int cmd_compress( string a ) /* a is the name of the file to be compressed */
{
  string old_file;
  string *old_lines;
  int number_lines;
  mixed arg;
  string old_file_name, new_file_name;

  if( !a ) { help(); notify_fail( "No argument passed.\n" ); return 0; }
  if( 2 != sscanf( a, "%s to %s", old_file_name, new_file_name ) &&
      2 != sscanf( a, "%s %s", old_file_name, new_file_name )       )
  {
    old_file_name = a;
    new_file_name = a + ".comp";
  }
  seteuid( getuid( previous_object() ) );
  old_file_name = resolv_path( this_player()-> query( "cwd" ), old_file_name );
  new_file_name = resolv_path( this_player()-> query( "cwd" ), new_file_name );
  switch( file_size( old_file_name ) )
  {
    case -2: notify_fail( "compress: " + old_file_name + ": directory\n" ); return 0;
    case -1: notify_fail( "compress: " + old_file_name + ": no such file\n" ); return 0;
  }
  if( !master()-> valid_read( old_file_name,
    (string)this_player()-> query( "name" ), "compress" ) )
  {
    notify_fail( old_file_name + ": Permission denied.\n" );
    return 0;
  }
  old_file = read_file( old_file_name );
  if( !old_file ) { notify_fail( old_file_name + " is empty.\n" ); return 0; }
  if( !master()-> valid_write( new_file_name,
    (string)this_player()-> query( "name" ), "compress" ) )
  {
    notify_fail( new_file_name + ": Permission denied.\n" );
    return 0;
  }
  if( file_size( new_file_name ) != -1 )
  {
    notify_fail( "compress: " + new_file_name + ": already exists.\n" );
    return 0;
  }
  old_lines = explode( old_file, "\n" );
  number_lines = sizeof( old_lines );
  arg = ({
    0,                         /* line number to start on                  */
    number_lines,              /* the number of lines in the file          */
    old_lines,                 /* the file, as an array of its lines       */
    ({ }),                     /* an array for the new version to go into  */
    new_file_name,             /* the file name for the compressed version */
    this_player(),             /* so messages can be given by the call_out */
    0,                         /* so text inside comment marks is unaltered */
  });
  call_out( "compress_lines", 1, arg );
  write( "Please wait " + (number_lines/LIMIT + 1) + " seconds.\n" );
  return 1;
/*
  There is a limit on the number of lines the machine can compress a second.
  If the file has more than this number, call_out must be used to 
  split the processing into chunks to avoid getting the
  "too many executions" error.
*/
}

void compress_lines( mixed a ) /* array a contains a mixture of variables */
{
  string file_name;
  string *old_lines, *new_lines;
  string old_line, new_line;
  int number_lines, line_number, char_number;
  int inside_comment, inside_quotes, line_started, ignore_next;
  int line_ended; // used for this type of comment.
  int limit, add_ch;
  string ch, last_ch, next_ch;
  object player;

  line_number    = a[0];
  number_lines   = a[1];
  old_lines      = a[2];
  new_lines      = a[3]; 
  file_name      = a[4];
  player         = a[5];
  inside_comment = a[6];

  limit = line_number + LIMIT;
  if( limit > number_lines ) limit = number_lines;
  for( ; line_number < limit ; line_number ++ )
  {
/*************** START OF BIT THAT COMPRESSES A SINGLE LINE ****************/
    old_line = old_lines[line_number];
    new_line = "";
    inside_quotes = 0;   /* 0 when outside "" marks, 1 when inside */
    line_started = 0;    /* 0 until the first non-space char in the line */
    line_ended = 0;      // 0 until reach this type of comment.
    ignore_next = 0;     /* Used to cope with \ marks */
    next_ch = old_line[0..0];
    ch = "";
    for( char_number = 0 ; char_number < strlen( old_line ) ; char_number ++ )
    {
      last_ch = ch;
      ch = next_ch;
      next_ch = old_line[(char_number+1)..(char_number+1)];
         /* NB old_line[(char_number+1)] would get a number not a string */
      add_ch = 1;    /* ch gets added to new_line if add_ch remains 1 */
      if( inside_comment || line_ended ) {
        if( ch == "*" && next_ch == "/" ) inside_comment = 0;
         /* If you are inside a comment, check for the end of it. */
         /* add_ch unaltered - text inside coments is copied verbatim */
      } else if( ch != " " && ch != TAB ) {
            /* space and tab are the only chars we delete during compression */
        line_started = 1;  /* we have found a non-space character */
        if( ignore_next ) ignore_next = 0;
        else if( ch == "\\" ) ignore_next = 1;
        else if( ch == "\"" ) inside_quotes = 1 - inside_quotes;
        else if( inside_quotes );
        else if( ch == "/" && next_ch == "*" ) inside_comment = 1;
        else if( ch == "/" && next_ch == "/" ) line_ended = 1;
      } else {
        if( !line_started ) add_ch = 0;
             /* delete all spaces at start of lines */
        else if( !ignore_next && !inside_quotes &&
              /* don't delete spaces inside quotes or comments */
          ( next_ch == " " || next_ch == "" ||
              /* delete more than single spaces and those at end of lines */
            waste_ch( last_ch ) || waste_ch( next_ch ) ||
              /* Delete spaces beside certain characters (see waste_ch() ) */
            next_ch == TAB || last_ch == "<"              ) )
               /* Don't delete spaces before < marks because of includes. */
          add_ch = 0;  /* don't add this ch becuase it is an unwanted space */
      }
      if( add_ch ) new_line += ch;
    }
    new_lines += ({ new_line });
/*************** END OF BIT THAT COMPRESSES A SINGLE LINE ****************/
  }
/* If havn't finished, compress the next bunch of lines */
  if( line_number < number_lines )
  {
    call_out( "compress_lines", 1, ({
      line_number,
      number_lines,
      old_lines,
      new_lines,
      file_name,
      player,
      inside_comment,
    }) );
    tell_object( player, "Lines " + (line_number-LIMIT) + " to " +
      line_number + " compressed.\n" );
    return;
  }
  return resave_file( new_lines, file_name, player );
/* Save the compressed file */
}

/* string array new_lines, string file_name, object player */
void resave_file( mixed new_lines, string file_name, object player )
{
  string new_file;
  mixed err;

  new_file = implode( new_lines, "\n" );
      /* turn the array of lines back into one string */
  new_file += "\n";
  if( err = catch( write_file( file_name, new_file ) ) )
    tell_object( player, "Error: " + err + "\n" );
  else tell_object( player, "Compressed version saved to: " + file_name + "\n");
}

/*
  a is a single character in the form of a string
  This function checks if the ch is one of the characters, next
   to which spaces can be safely deleted.
*/
int waste_ch( string a )
{
  switch( a )
  {
    case "+":  return 1;
    case "-":  return 1;
    case "=":  return 1;
    case ",":  return 1;
    case ";":  return 1;
    case "(":  return 1;
    case ")":  return 1;
    case "{":  return 1;
    case "}":  return 1;
    case ">":  return 1;
    case "|":  return 1;
    case "&":  return 1;
    case "!":  return 1;
    default:   return 0;
  }
/* returns 1 if the space can be deleted, 0 if it can't */
}

string help()
{
  write( ""+
"Syntax: compress <file>[ to <new_file>]\n"+
"Effect: Removes spaces in the file that are unnecessary\n"+
"        for the code to work and copies the version to\n"+
"        <new_file> (which defaults to <file>.comp)\n"+
  "" );
}