#!/usr/bin/env perl
#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-

# Boot manager configurator: YABOOT-related routines.
#
# Copyright (C) 2001 Ximian, Inc.
#
# Authors: Carlos Garnacho Parro  <garnacho@tuxerver.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library General Public License as published
# by the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.


$SCRIPTSDIR = "/usr/share/setup-tool-backends/scripts";
if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
{
    $SCRIPTSDIR = ".";
    $DOTIN = ".in";
}

require "$SCRIPTSDIR/general.pl$DOTIN";
require "$SCRIPTSDIR/util.pl$DOTIN";
require "$SCRIPTSDIR/file.pl$DOTIN";
require "$SCRIPTSDIR/xml.pl$DOTIN";
require "$SCRIPTSDIR/parse.pl$DOTIN";
require "$SCRIPTSDIR/replace.pl$DOTIN";
require "$SCRIPTSDIR/partition.pl$DOTIN";

my @yaboot_global_vars = qw (default prompt delay timeout append boot root);
my @yaboot_image_vars = qw (label image append initrd root);
my @yaboot_other_vars = qw (bsd macos macosx darwin);

sub gst_boot_yaboot_verify
{
  return "success";
}

sub gst_boot_yaboot_parse_entries
{
  my ($file, $partition, $root) = @_;
  my ($fd, $line, @entries, $entry);
  my ($line, $known_vars, $found);

  $found = -1;

  $fd = &gst_file_open_read_from_names ($file);
  if (! $fd)
  {
    &gst_report ("boot_conf_read_failed", $file);
    return undef;
  }

  while (($line = <$fd>))
  {
    chomp $line;
    $line =~ s/^[ \t]+//;

    if ($line =~ /^image/i)
    {
      $found++;
      $known_vars = \@yaboot_image_vars;
      $entries[$found]{"key"} = $found;
    }
    elsif ($line =~ /^(bsd|macos|macosx|darwin)/)
    {
      $found++;
      $known_vars = \@yaboot_other_vars;
      $entries[$found]{"key"} = $found;
    }
    
    next if $found < 0;
    
    next if $line =~ /^\#/;

    $line = &gst_parse_process_sh_line ($line);
    next if $line eq "";
    
    my @line = split ("[ \t]*=[ \t]*", $line, 2);    
    my $key = shift @line;

    # Only deal with known variables
    next unless &gst_boot_lilo_known_var ($key, $known_vars, 0);
    
    my $val = shift @line;
    $val =~ s/^[ \t]+//;
    $val =~ s/\"//g;    
    $val =~ s/[ \t]+$//;

    if ($key =~ /^(bsd|macos|macosx|darwin)$/)
    {
      $entries[$found]{"label"} = $key;
      $key = "other";
    }

    $entries[$found]{$key} = $val;

    # the root parameter may not exist, then we take the global parameter
    if (($entries[$found]{"root"} eq undef) && ($entries[$found]{"image"} ne undef))
    {
      $entries[$found]{"root"} = $root;
    }
  }

  &gst_file_close ($fd);

  foreach $entry (@entries)
  {
    &gst_boot_lilo_set_default_type ($entry, $partition);
  }

  return \@entries;
}

sub gst_boot_yaboot_find_entry
{
  my ($buff, $lineno) = @_;
  my $i;

  for (; $lineno <= $#$buff; $lineno++)
  {
    $i = $$buff[$lineno];

    return $lineno if ($i =~ /^[ \t]*(image|bsd|macos|macosx|darwin)[ \t]*=[ \t]*\S+/);
  }

  # Not found.
  return -1;
}

sub gst_boot_yaboot_delete_entry
{
  my ($buff, $lineno) = @_;
  my ($end, $i);

  $end = &gst_boot_yaboot_find_entry ($buff, $lineno + 1);
  $end = scalar @$buff if ($end < 0);

  for ($i = $lineno; $i < $end; $i++)
  {
    $$buff[$i] = "";
  }

  return $buff;
}

sub gst_boot_yaboot_edit_entry
{
  my ($entry, $buff, $lineno) = @_;

  my $known_vars = \@yaboot_image_vars if (exists $entry->{'image'});
  $known_vars = \@yaboot_other_vars if (!$known_vars && exists $entry->{'other'});
  return $buff unless $known_vars;

  my $end = &gst_boot_yaboot_find_entry ($buff, $lineno + 1);
  $end = scalar @$buff if ($end < 0);

  for ($lineno; $lineno < $end; $lineno++)
  {
    # Get the variable.
    my $key = $1 if ($$buff[$lineno] =~ /^[ \t]*([\w\-]+)/);
    next if ($key && (!&gst_boot_lilo_known_var ($key, $known_vars, 0)));
    next unless $key;

    if (exists ($entry->{"other"}))
    {
      my $old_val = $$buff[$lineno];
      $old_val =~ s/^[ \t]*$key[ \t]*=[ \t]*//; #everything till value
      $old_val =~ s/[ \t]*\#.*$//;              #post comment;
      chomp $old_val;

      if ($old_val)
      {
        # String.
        my $val = $entry->{"other"};
        $val = "\"$val\"" if ($val =~ /[ \t]/ && (! ($val =~ /^\".+\"$/)));
        $val = "\"$val\"" if ($val =~ /\=/ && (!($val =~ /^\".+\"$/)));

        $$buff[$lineno] =~ s/$old_val/$val/;
      }
    }
    else
    {
      unless (exists ($entry->{$key}))
      {
        # Keyword is known, but isn't in entry.
        delete $$buff[$lineno];
        next;
      }

      # Read old value
      my $old_val = $$buff[$lineno];
        
      $old_val =~ s/^[ \t]*$key[ \t]*=[ \t]*//; #everything till value
      $old_val =~ s/[ \t]*\#.*$//;              #post comment;
      chomp $old_val;

      if ($old_val)
      {
        # String.
        my $val = $entry->{$key};
        $val = "\"$val\"" if ($val =~ /[ \t]/ && (! ($val =~ /^\".+\"$/)));
        $val = "\"$val\"" if ($val =~ /\=/ && (!($val =~ /^\".+\"$/)));

        $$buff[$lineno] =~ s/$old_val/$val/;
      }
    
      delete $entry->{$key};
    }
  }

  # Add new fields.
  foreach my $key (keys %$entry)
  {
    next unless &gst_boot_lilo_known_var ($key, $known_vars, 1);
      
    my $val = $entry->{$key};
    $val = "\"$val\"" if ($val =~ /[ \t]/ && (! ($val =~ /^\".+\"$/)));
    $val = "\"$val\"" if ($val =~ /\=/ && (!($val =~ /^\".+\"$/)));

    my $line = "\t$key";;
    
    $line .= " = $val" if $val;
    $line .= "\n";
    
    $$buff[$end -1] .= $line;
  }
}

# Add $entry to the end of $buff.
sub gst_boot_yaboot_add_entry
{
  my ($entry, $buff) = @_;
  my ($line, $key, $value, $known_vars);

  # Entry line
  if (exists $entry->{'image'})
  {
    $known_vars = \@yaboot_image_vars;
    $value = 'image';

    $line = $value . " = " . $$entry{$value} . "\n";
  }
  elsif (exists $entry->{'other'})
  {
    $known_vars = \@yaboot_other_vars;

    # FIXME: this is a really terrible hack, the xml needs to be redesigned
    if ($entry->{'label'} =~ /(macos|macosx|bsd|darwin)/)
    {
      $value = $entry->{'label'};
    }
    else
    {
      $value = 'macosx';
    }

    $line = $value . " = " . $$entry{"other"} . "\n";
  }
  else
  {
    return;
  }

  push @$buff, $line;
  delete $$entry{$value};
  
  # Parameters for entry
  foreach $key (keys %$entry)
  {
    next unless &gst_boot_lilo_known_var ($key, $known_vars, 1);
    
    $value = $$entry{$key};
    $value = "\"$value\"" if ($value =~ /[ \t]/ && (!($value =~ /^\".+\"$/)));
    $value = "\"$value\"" if ($value =~ /\=/&& (!($value =~ /^\".+\"$/)));

    $line = "\t$key";

    $line .= " = " . $value if $value;
    $line .= "\n";

    push @$buff, $line;
  }
}

sub gst_boot_yaboot_entries_set
{
  my ($file, $entries) = @_;
  my ($buff, $lineno, $found, $entry);

  return if (scalar @$entries <= 0);
  
  $buff = &gst_file_buffer_load ($file);
  &gst_file_buffer_join_lines ($buff);

  my $entry_nr = -1;
  $lineno = &gst_boot_yaboot_find_entry ($buff, 0);

  while ($lineno > 0)
  {
    $entry_nr++;
    $found = 0;

    foreach $entry (@$entries)
    {
      next unless $entry;

      if (exists ($entry->{"key"}))
      {
        $found++ if $entry->{"key"} == $entry_nr;

        if ($found > 0)
        {
          # Found entry, change it if necessary,
          # remove %entry from @entries and find new entry.
          &gst_boot_yaboot_edit_entry ($entry, $buff, $lineno);
          $entry = undef;
          last;
        }
      }
    }

    # Found entry wasn't in our @entries list: delete.
    $buff = &gst_boot_yaboot_delete_entry ($buff, $lineno) if ($found <= 0);

    # Search new entry line.
    $lineno = &gst_boot_yaboot_find_entry ($buff, $lineno + 1);
  }

  # At this point @entries contains only new entries, let's add them.
  foreach $entry (@$entries)
  {
    next if ($entry eq undef);
    &gst_boot_yaboot_add_entry ($entry, $buff);
  }

  &gst_file_buffer_clean ($buff);
  return &gst_file_buffer_save ($buff, $file);
}
