ldmud-3.3.719/
ldmud-3.3.719/doc/
ldmud-3.3.719/doc/efun.de/
ldmud-3.3.719/doc/efun/
ldmud-3.3.719/doc/man/
ldmud-3.3.719/doc/other/
ldmud-3.3.719/mud/
ldmud-3.3.719/mud/heaven7/
ldmud-3.3.719/mud/lp-245/
ldmud-3.3.719/mud/lp-245/banish/
ldmud-3.3.719/mud/lp-245/doc/
ldmud-3.3.719/mud/lp-245/doc/examples/
ldmud-3.3.719/mud/lp-245/doc/sefun/
ldmud-3.3.719/mud/lp-245/log/
ldmud-3.3.719/mud/lp-245/obj/Go/
ldmud-3.3.719/mud/lp-245/players/lars/
ldmud-3.3.719/mud/lp-245/room/death/
ldmud-3.3.719/mud/lp-245/room/maze1/
ldmud-3.3.719/mud/lp-245/room/sub/
ldmud-3.3.719/mud/lp-245/secure/
ldmud-3.3.719/mud/sticklib/
ldmud-3.3.719/mud/sticklib/src/
ldmud-3.3.719/mudlib/deprecated/
ldmud-3.3.719/mudlib/uni-crasher/
ldmud-3.3.719/pkg/
ldmud-3.3.719/pkg/debugger/
ldmud-3.3.719/pkg/diff/
ldmud-3.3.719/pkg/misc/
ldmud-3.3.719/src/
ldmud-3.3.719/src/autoconf/
ldmud-3.3.719/src/ptmalloc/
ldmud-3.3.719/src/util/
ldmud-3.3.719/src/util/erq/
ldmud-3.3.719/src/util/indent/hosts/next/
ldmud-3.3.719/src/util/xerq/
ldmud-3.3.719/src/util/xerq/lpc/
ldmud-3.3.719/src/util/xerq/lpc/www/
ldmud-3.3.719/test/generic/
ldmud-3.3.719/test/inc/
ldmud-3.3.719/test/t-0000398/
ldmud-3.3.719/test/t-0000548/
ldmud-3.3.719/test/t-030925/
ldmud-3.3.719/test/t-040413/
ldmud-3.3.719/test/t-041124/
ldmud-3.3.719/test/t-language/
#!/usr/bin/perl -w
######
#
# Parse a mudmode (save_value) string
#
# A single variable value is parsed and represented as perl data structure.
# So a string like '({"a",3,(["b":2,]),})' gets ['a',3,{'b'=>2}]
#
# Fiona 23-Mai-03
#

use Data::Dumper;

$parse_err = undef; # Global error messages

%unquote = (
  'r' => "\r",
  'f' => "\f",
  'v' => "\v",
  'n' => "\n",
  't' => "\t",
  'b' => "\b",
  'a' => "\a",
);

# parse a single value
#
# Knows: int, string, array, float, mapping
# (Todo: ref_to_array/mapping, closures)
# 
# arguments: source string
#            reference to start index of value
# returns value in perl
# set start index to next char (if any) or -1
#
# If an error occured -1 will be returned and $parse_err set

sub get_value {
  my ($offsp, $str, $ret, $ret2, $data);
  $str = $_[0];
  $offsp = $_[1];

  # check for float
  #
  # [German:Koresh@OuterSpace] OS would encode it as  #-1.00000001e-01#  but
  #         not sure everybody does it this way.
  # [German:Fiona] means ({-0.1}) becomes ({#-1.00000001e-01#,})  ?
  # [German] Koresh@OuterSpace nods wildly
  # [German] Koresh@OuterSpace also notes that mudos does not seem  to include
  #         the # in floats: it just writes it as ({-1.00000e-08,})
  #
  # LDmud float
  # -9.999999997672e-02=fffd:9999999a

  pos($str) = $$offsp;
  $str =~ m/\G#?(-?\d.\d*[eE][-+]\d\d)(#|=[0-9a-f:]+)?/sg;
  if (defined $1) {
    $$offsp = pos($str);
    return $1;
  }

  # check for int (check *after* floats)
  pos($str) = $$offsp;
  $str =~ m/\G(-?\d+)/sg;
  if (defined $1) {
    $$offsp = pos($str);
    return $1;
  }

  # check for string
  pos($str) = $$offsp;
  if ($str =~ m/\G"((?:[^"\\]+|\\.)*)"/sg ) {
    $$offsp = pos($str);
    # unquote string
    $ret = $1;
    $ret =~ s/\\(.)/$unquote{$1}||$1/esg;
    return $ret;
  }

  # check for array
  pos($str) = $$offsp;
  if ($str =~ m/\G\({/sg ) {
    $$offsp = pos($str);
    $data = [];

    if ($str =~ m/\G}\)/sg ) {
      $$offsp += 2;
      return $data;
    }

    # recurse array
    while (1) {
      $ret = get_value($str, $offsp);
      return -1 if ($parse_err || $offsp == -1);

      push @{$data}, $ret;

      pos($str) = $$offsp;
      if (not ($str =~ m/\G,/sg )) {
        pos($str) = $$offsp;
        $str =~ m/\G(.{0,8})/sg;
        $parse_err = "Comma missing in array near '$1'";
	return -1;
      }
      $$offsp += 1;

      if ($str =~ m/\G}\)/sg ) {
        $$offsp += 2;
        return $data;
      }
    }
    # notreached
  }

  # check for mapping
  #
  # MudOS has no 2dimensional Mappings, so we dont support them
  # (perl is unable to represent them anyhow)
  # Zero-width mappings are impossible with mudmode/perl, so emulate them.

  pos($str) = $$offsp;
  if ($str =~ m/\G\(\[/sg ) {
    $$offsp = pos($str);
    $data = {};

    if ($str =~ m/\G]\)/sg ) {
      $$offsp += 2;
      return $data;
    }

    # recurse array
    while (1) {
      $ret = get_value($str, $offsp);
      return -1 if ($parse_err || $offsp == -1);


      pos($str) = $$offsp;
      if (not ($str =~ m/\G[:,]/sg )) {
        pos($str) = $$offsp;
        if ($str =~ m/\G;/sg ) {
          $parse_err = 'Multidimensional mapping not supported near ';
        } else {
          $parse_err = 'Colon missing in mapping near ';
        }
        pos($str) = $$offsp;
        $str =~ m/\G(.{0,8})/sg;
        $parse_err = $parse_err . "'$1'";
	return -1;
      }
      $$offsp += 1;

      pos($str) = $$offsp-1;
      if ($str =~ m/\G,/sg ) { # zero width, gets simulated...
        $ret2 = 0;
      } else {
        $ret2 = get_value($str, $offsp);
        return -1 if ($parse_err || $offsp == -1);

        pos($str) = $$offsp;

        if (not ($str =~ m/\G,/sg )) {
          pos($str) = $$offsp;
          $str =~ m/\G(.{0,8})/sg;
          $parse_err = "Comma missing in mapping near '$1'";
	  return -1;
        }
        $$offsp += 1;
      }

      $$data{$ret} = $ret2;

      if ($str =~ m/\G]\)/sg ) {
        $$offsp += 2;
        return $data;
      }
    }
    # notreached
  }

  # check for parse error
  pos($str) = $$offsp;
  $str =~ m/\G(.{1,8})/sg;
  if (defined $1) {
    $parse_err = "Unknown variable type near '$1'";
    return -1;
  }

  # end of string
  $$offsp = -1;
  return -1;
}

######
#
# Sample usage
#

$str = '({1234,45,({12,-1,({0,}),}),"fla\nb\"ber",-1.110999999642e+02=7:90e66667,({}),(["b":"a","c":({1,-2,}),]),([1,2,3,]),})';

#$str='({"error",5,"*gjs",0,"Test-PerlMud-i3",0,"unk-src","router does not know you",({"startup-req-3",5,"Test-PerlMud-i3",0,"",0,1016,4156424,330,0,0,0,"PerlLib v1","PerlLib v1","Perlv5.6.1","Perl","restricted access","castaway@desert-island.m.isar.de",(["channel":1,"nntp":0,"file":0,"amcp":0,"rcp":0,"emoteto":1,"auth":0,"who":1,"smtp":0,"mail":0,"finger":1,"ucache":1,"locate":1,"news":0,"http":0,"ftp":0,"tell":1,]),0,}),})';

$posi = 0;
$ret = get_value($str, \$posi);

if ($parse_err) {
  print("ERROR $parse_err\n");
} else {
  print(Dumper($ret));
}