User Control Panel
Advertisements

HELP US, HELP YOU!

EOL doesn't like me

 
Post new topic   Reply to topic    Bot Depot Forum Index -> Perl
View unanswered posts
Author Message
Cer
Upgraded Agent
Upgraded Agent


Joined: 03 Feb 2004
Posts: 3776
Location: Michigan
Reputation: 146.9
votes: 4

PostPosted: Sun Jan 22, 2006 5:06 pm    Post subject: EOL doesn't like me Reply with quote

Okay, here's the dillemma: end-of-line characters don't like me.

I was recently writing this module Config::INI::Simple for reading and writing from config INI files. I figured this time around I'd handle files "correctly" and put in the right EOL symbols, based on the OS.

So for Windows, I had it do something like this:
Code:
open (WRITE, ">$file");
print WRITE join ("\r\n", @lines);
close (WRITE);


When viewed in Notepad afterward, everything looked just fine. I ran the script again to read from $file again, but this time around when it saved back to $file, there was one of those block symbols at the end of each line (but there were still multiple lines). It looked like this:

Code:
; Test INI Script[]
; Pick a server from below[]
server=Server02[]
[]
; Every server should have[]
; a host and a port, in the[]
; form host=address and[]
; port=number[]
[Server01][]
host=foo.bar.com[]
port=6665[]
[]
[Server02][]
...and-so-on[]


Where each [] was one of those block symbols. Running the script again, Perl flipped out with lots of warnings of uninitialized variables, because it was programmed to skip blank lines... but with these symbols ON the blank lines, it wasn't skipping them.

I'm assuming these symbols were caused by the \r, because I always just used \n on Windows and it made good-looking Notepad sources. But isn't the Windows EOL \r\n?

On a recent CGI project, there was a link to download a RiveScript source. An RS file is inherently plaintext, so it used content-disposition to send it as a download. When the script joined the source at \n, Windows showed it as a one-line source with blocks where the newlines should be. I set it to \r\n, and Windows viewed the lines correctly.

As far as my Config::INI::Simple went, I had it use \n instead of \r\n. It may not be the native Windows EOL but it's what I've been using forever, Windows doesn't complain about it, and it's the Linux EOL (right?) so the best of both worlds.

But, the issue arose again lately...

I dug up my old Archive::Tyd module and was going to create a GUI interface for it, similar to WinZip for Zip files. It all worked well to begin with, but there was a serious issue...

1) Create a new archive, add files, etc etc
2) Save the archive to a Tyd file
3) Open the archive again through the module
4) Save it again

And upon the second save, the EOL became an issue again. It wasn't translating the \r's and \n's in the files anymore, so when opening the archive again, it would come out with a bunch of gibberish instead of the file names--or their contents.

I'm assuming it's the same issue here. The module converted \r and \n within each file into placeholders, and the final Tyd file was a line-by-line, where each line was a different file and its contents.

So I'm assuming that when it was saved a second time, the EOL errors came back to bite me and that's how it messed up.

So can anyone point me to a good tutorial that explains possibly how you're supposed to handle EOL's?

_________________
Current Site (2008) http://www.cuvou.com/
Back to top
Mojave
Almost An Agent
Almost An Agent


Joined: 01 Nov 2003
Posts: 1434

Reputation: 66.4

PostPosted: Sun Jan 22, 2006 5:34 pm    Post subject: Reply with quote

Something you're not showing us is the code you use to read in your config files. It seems like maybe through one read/write cycle that extra characters are being added, but I'd need to see the read code to determine that.

Also, I'm not sure why you have to add \r for any OS. I guess I don't know what you mean by "correctly". My code that reads and writes text files on both Windows and Linux is identical and uses only \n. It works fine in both and is readable in a text editor on both.
Back to top
Cer
Upgraded Agent
Upgraded Agent


Joined: 03 Feb 2004
Posts: 3776
Location: Michigan
Reputation: 146.9
votes: 4

PostPosted: Sun Jan 22, 2006 8:39 pm    Post subject: Reply with quote

Right, here's my code:

Code:
package Config::INI::Simple;

use strict;
use warnings;

our $VERSION = '0.01';

sub new {
   my $proto = shift;
   my $class = ref($proto) || $proto || 'Config::INI::Simple';

   my $self = {
      __file__    => undef,
      __default__ => 'default',
      __eol__     => "\r\n",
      __append__  => 1,
      @_,
   };

   bless ($self,$class);
   return $self;
}

sub reset {
   my ($self) = @_;

   $self = {
      __file__    => $self->{__file__},
      __default__ => $self->{__default__},
      __eol__     => $self->{__eol__},
      __append__  => $self->{__append__},
   };
}

sub read {
   my ($self,$file) = @_;

   if (!defined $file) {
      $file = $self->{__file__};
      return unless defined $file;
   }

   return unless -e $file;

   $self->{__file__} = $file;

   open (FILE, $file);
   my @lines = <FILE>;
   close (FILE);
   chomp @lines;

   my $data = {};
   my $block = $self->{__default__} || 'default';

   foreach my $line (@lines) {
      $line =~ s/\r//g;
      $line =~ s/\n//g;
      if ($line =~ /\s*\[(.*?)\]\s*/) {
         $block = $1;
         next;
      }

      next if $line =~ /^\s*\;/;
      next if $line =~ /^\s*\#/;

      next if length $line == 0;
      my ($what,$is) = split(/=/, $line, 2);
      $what =~ s/^\s*//g;
      $what =~ s/\s*$//g;
      $is =~ s/^\s*//g;
      $is =~ s/\s*$//g;

      $data->{$block}->{$what} = $is;
   }

   foreach my $block (keys %{$data}) {
      $self->{$block} = $data->{$block};
   }

   return 1;
}

sub write {
   my ($self,$file) = @_;

   if (!defined $file) {
      $file = $self->{__file__};
      return unless defined $file;
   }

   return unless -e $file;

   open (FILE, $file);
   my @lines = <FILE>;
   close (FILE);
   chomp @lines;

   my $block = $self->{__default__} || 'default';
   my @new = ();
   my $used = {};

   foreach my $line (@lines) {
      if ($line =~ /\s*\[(.*?)\]\s*/) {
         $block = $1;
         $line =~ s/^\s*//g;
         $line =~ s/\s*$//g;
         push (@new, $line);
         next;
      }

      if ($line =~ /^\s*\;/ || $line =~ /^\s*\#/) {
         push (@new, $line);
         next;
      }

      if (length $line == 0) {
         push (@new, '');
         next;
      }

      my ($what,$is) = split(/=/, $line, 2);
      $what =~ s/^\s*//g;
      $what =~ s/\s*$//g;
      $is =~ s/^\s*//g;
      $is =~ s/\s*$//g;

      if (exists $self->{$block}->{$what}) {
         $line = join ('=', $what, $self->{$block}->{$what});
         $used->{$block}->{$what} = 1;
      }

      push (@new, $line);
   }

   # Add new config variables?
   if ($self->{__append__} == 1) {
      foreach my $key (keys %{$self}) {
         next if $key =~ /^__.*?__$/i;
         print "Checking key $key (ref = " . ref($key) . ")\n";

         if (!exists $used->{$key}) {
            print "Block doesn't exist!\n";
            push (@new, "");
            push (@new, "[$key]");
         }

         foreach my $lab (keys %{$self->{$key}}) {
            if (!exists $used->{$key}->{$lab}) {
               print "Adding $lab=$self->{$key}->{$lab} to INI\n";
               push (@new, "$lab=$self->{$key}->{$lab}");
            }
         }
      }
   }

   my $eol = $self->{__eol__} || "\r\n";
   open (WRITE, ">$file");
   print WRITE join ($eol, @new);
   close (WRITE);

   return 1;
}

1;
__END__


Subs read and write are the ones that read and write the files.

_________________
Current Site (2008) http://www.cuvou.com/
Back to top
Display posts from previous:   
Post new topic   Reply to topic    Bot Depot Forum Index -> Perl All times are GMT
Page 1 of 1

 



Protected by phpBB Security phpBB-TweakS
phpBB Security Has Blocked 9 Exploit Attempts.
Antispam Captcha Mod by phpbb-security.com
Powered by phpBB © 2001, 2005 phpBB Group