package CParse::String;

use 5.6.0;
use strict;
use warnings;

use Exporter;

our @ISA = qw/Exporter/;
our @EXPORT_OK = qw/escape unescape/;

sub escape
  {
    my $str = shift;
    $str =~ s/\\/\\\\/g;
    $str =~ s/\'/\\'/g;
    $str =~ s/\"/\\"/g;
    $str =~ s/\?/\\?/g;
    $str =~ s/\a/\\a/g;
    $str =~ s/\0x08/\\b/g;
    $str =~ s/\f/\\f/g;
    $str =~ s/\n/\\n/g;
    $str =~ s/\r/\\r/g;
    $str =~ s/\t/\\t/g;
    $str =~ s/\0x0b/\\v/g;
    $str =~ s/([^[:print]])/sprintf "\\x%x", ord($1)/ge;
    return $str;
  }

sub unescape
  {
    my $str = shift;
    my $out = "";

    while (length $str)
      {
        my $c = substr($str, 0, 1, '');
        if ($c eq '\\')
          {
            $c = substr($str, 0, 1, '');
            unless (defined $c)
              {
                die "Bad escape sequence\n";
              }
            if ($c eq '\\')
              {
                $out .= '\\';
              }
            elsif ($c eq '\'')
              {
                $out .= '\'';
              }
            elsif ($c eq '"')
              {
                $out .= '"';
              }
            elsif ($c eq '?')
              {
                $out .= '?';
              }
            elsif ($c eq 'a')
              {
                $out .= "\a";
              }
            elsif ($c eq 'b')
              {
                $out .= "\0x08";
              }
            elsif ($c eq 'f')
              {
                $out .= "\f";
              }
            elsif ($c eq 'n')
              {
                $out .= "\n";
              }
            elsif ($c eq 'r')
              {
                $out .= "\r";
              }
            elsif ($c eq 't')
              {
                $out .= "\t";
              }
            elsif ($c eq 'v')
              {
                $out .= "\0x0b";
              }
            elsif ($c eq 'x')
              {
                $str =~ s/^([[:xdigit:]]+)//;
                $out .= chr(hex($1));
              }
            elsif ($c =~ /^[0-7]$/)
              {
                $str =~ s/^([0-7]{0,2})//;
                $out .= chr(oct($c . $1));
              }
          }
        else
          {
            $out .= $c;
          }
      }

    return $out;
  }

sub new
  {
    my $this = shift;
    my $class = ref($this) || $this;

    my $str = shift;
    my $wide = shift;

    my $self = {value => $str,
                wide => $wide,
               };
    bless $self, $class;
    return $self;
  }

sub dump_c
  {
    my $self = shift;

    my $value = escape($self->{value});

    return $self->{wide} ? "L\"$value\"" : "\"$value\"";
  }

1;
