#!/usr/bin/perl
package Debian::DictionariesCommon;
use strict;
use base qw(Exporter);
use Text::Iconv;
# List all exported symbols here.
our @EXPORT_OK = qw(parseinfo updatedb loaddb
dico_checkroot
dico_debug
dico_debugprint
dico_get_spellchecker_params
getlibdir
dico_getsysdefault dico_setsysdefault
getuserdefault setuserdefault
dico_find_matching_choice
build_emacsen_support
build_jed_support
build_squirrelmail_support
dico_activate_trigger
dico_clean_orphaned_removefiles
dico_preprocess_default_symlinks
dico_set_default_symlink
);
# Import :all to get everything.
our %EXPORT_TAGS = (all => [@EXPORT_OK]);
my $infodir = "/var/lib/dictionaries-common";
my $cachedir = "/var/cache/dictionaries-common";
my $emacsensupport = "emacsen-ispell-dicts.el";
my $jedsupport = "jed-ispell-dicts.sl";
my $squirrelmailsupport = "sqspell.php";
my $debug = 1 if ( defined $ENV{'DICT_COMMON_DEBUG'} );
# Directories and files to store default values
my $sys_etc_dir = "/etc/dictionaries-common";
my $sys_default_dir = "$cachedir";
my $ispelldefault = "ispell-default";
my $userdefault = ( defined $ENV{HOME} ) ? "$ENV{HOME}/.$ispelldefault" : undef;
my %sys_default_file = ("ispell" => "$sys_default_dir/ispell-default",
"wordlist" => "$sys_default_dir/wordlist-default");
# ------------------------------------------------------------------
sub dico_checkroot {
# ------------------------------------------------------------------
# Check if we are root
# ------------------------------------------------------------------
return if ($> == 0 or ($^O eq 'interix' and $> == 197108));
die "$0: You must run this as root.\n";
}
# -------------------------------------------------------------
sub dico_debug {
# -------------------------------------------------------------
# Enable debug mode
# -------------------------------------------------------------
$debug++;
$ENV{'DICT_COMMON_DEBUG'}++;
}
# -------------------------------------------------------------
sub dico_debugprint {
# -------------------------------------------------------------
# Show info if in debug mode
# -------------------------------------------------------------
print STDERR "@_\n" if $debug;
}
# ------------------------------------------------------------------
sub getlibdir {
# ------------------------------------------------------------------
# Get location for dict-common info snippets
# ------------------------------------------------------------------
my $class = shift;
return "$infodir/$class";
}
# ------------------------------------------------------------------
sub mydie {
# ------------------------------------------------------------------
# A wrapper to die with some local flavor.
# ------------------------------------------------------------------
my $routine = shift;
my $errmsg = shift;
die __PACKAGE__, "($routine):E: $errmsg";
}
# ------------------------------------------------------------------
sub parseinfo {
# ------------------------------------------------------------------
# Parse given dict-common info file
# ------------------------------------------------------------------
my $file = shift;
local $/ = ""; # IRS is global, we need 'local' here, not 'my'
open (DICT, "< $file");
my %dictionaries =
map {
s/^([^:]+):/lc ($1) . ":"/meg; # Lower case field names
my %hash = /^([^:]+):\s*((?<!\n)[^\n]+)\s*$/mg;
map { delete $hash{$_} if ($hash{$_} =~ /^\s+$/) } keys %hash;
mydie ('parseinfo',
qq{Record in file $file does not have a "Language" entry})
if not exists $hash{language};
mydie ('parseinfo',
qq{Record in file $file does not have a "Hash-Name" entry})
if not exists $hash{"hash-name"};
my $lang = delete $hash{language};
($lang, \%hash);
} <DICT>;
return \%dictionaries;
}
# ------------------------------------------------------------------
sub dico_dumpdb {
# ------------------------------------------------------------------
# Save %dictionaries in Data::Dumper like format. This function
# should be enough for the limited needs of dictionaries-common
# ------------------------------------------------------------------
my $class = shift;
my $dictionaries = shift;
my @fullarray = ();
my @dictarray = ();
my $output = "$cachedir/$class.db";
my $dictentries = '';
my $thevalue = '';
foreach my $thedict ( sort keys %{$dictionaries}){
$dictentries = $dictionaries->{$thedict};
@dictarray = ();
foreach my $thekey ( sort keys %{$dictentries}){
$thevalue = $dictentries->{$thekey};
# Make sure \ and ' are escaped in keyvals
$thevalue =~ s/(\\|\')/\\$1/g;
push (@dictarray," \'$thekey\' => \'$thevalue\'");
}
# Make sure \ and ' are escaped in dict names
$thedict =~ s/(\\|\')/\\$1/g;
push (@fullarray,
" \'$thedict\' => \{\n" . join(",\n",@dictarray) . "\n \}");
}
mkdir $cachedir unless (-d $cachedir);
open (DB,"> $output");
print DB generate_comment("### ") . "\n";
print DB "package Debian::DictionariesCommon::dbfile;\n\n";
print DB "%dictionaries = (\n";
print DB join (",\n",@fullarray);
print DB "\n);\n\n1;\n";
close DB;
}
# ------------------------------------------------------------------
sub dico_get_spellchecker_params {
# ------------------------------------------------------------------
# dico_get_spellchecker_params($class,\%language)
# Get right params for $class (currently unused) and $language
# ------------------------------------------------------------------
my $class = shift;
my $language = shift;
my $d_option = "";
my $w_option = "";
my $T_option = "";
my $ispell_args = "";
$d_option = "-d $language->{'hash-name'}"
if exists $language->{'hash-name'};
$w_option = "-w $language->{'additionalchars'}"
if exists $language->{'additionalchars'};
if ( exists $language->{'extended-character-mode'} ){
$T_option = $language->{'extended-character-mode'};
$T_option =~ s/^~//; # Strip leading ~ from Extended-Character-Mode.
$T_option = '-T ' . $T_option;
}
if ( exists $language->{'ispell-args'} ){
$ispell_args = $language->{'ispell-args'};
foreach ( split('\s+',$ispell_args) ) {
# No d_option if already in $ispell_args
$d_option = "" if /^\-d/;
}
}
return "$d_option $w_option $T_option $ispell_args";
}
# ------------------------------------------------------------------
sub updatedb {
# ------------------------------------------------------------------
# Parse info files for the given class and update class database
# ------------------------------------------------------------------
my $class = shift;
my %dictionaries = ();
foreach my $file (<$infodir/$class/*>) {
next if $file =~ m/.*~$/; # Ignore ~ backup files
my %dicts = %{ parseinfo ("$file") };
# Add package name to all entries
my $file_basename = $file;
$file_basename =~ s/^$infodir\/$class\///;
$dicts{$_}{'package'} = $file_basename foreach ( keys %dicts );
%dictionaries = (%dictionaries, %dicts);
}
&dico_dumpdb($class,\%dictionaries);
}
# ------------------------------------------------------------------
sub loaddb {
# ------------------------------------------------------------------
# Load class database
# ------------------------------------------------------------------
my $class = shift;
my $dbfile = "$cachedir/$class.db";
if (-e $dbfile) {
do $dbfile;
}
return \%Debian::DictionariesCommon::dbfile::dictionaries;
}
# ------------------------------------------------------------------
sub getdefault {
# ------------------------------------------------------------------
# Read default value from specified file. Comments and empty lines are ignored.
# ------------------------------------------------------------------
my $file = shift;
my $lang = "";
if (-f $file) {
open( my $FILE,"< $file")
or die "Dictionaries-common::getdefault: Could not open $file for read. Aborting ...\n";
while (<$FILE>){
next if m/^\s*\#/;
next if m/^\s*$/;
$lang = $_;
last;
}
close $FILE;
return $lang;
}
return;
}
# ------------------------------------------------------------------
sub getuserdefault {
# ------------------------------------------------------------------
# Get user default from user's default file
# ------------------------------------------------------------------
die "Dictionaries-common::getuserdefault: Could not set \$userdefault. Aborting ...\n"
unless $userdefault;
getdefault ($userdefault);
}
# ------------------------------------------------------------------
sub dico_getsysdefault {
# ------------------------------------------------------------------
# Get system default value for given class
# ------------------------------------------------------------------
my $class = shift;
getdefault ($sys_default_file{$class});
}
# ------------------------------------------------------------------
sub dico_setsysdefault {
# ------------------------------------------------------------------
# Set system default value for given class
# ------------------------------------------------------------------
my $class = shift;
my $value = shift;
my $default_file = "$sys_default_file{$class}";
my $old_ispell_default = "$sys_etc_dir/$ispelldefault";
if ( "$value" ){
open (DEFAULT, "> $default_file");
print DEFAULT $value;
close DEFAULT;
# Set symlink from old to new location for squirrelmail benefit.
if ( $class eq "ispell" ){
unlink "$old_ispell_default";
symlink "$default_file", "$old_ispell_default";
}
} else {
unlink "$default_file" if ( -e "$default_file" );
# squirrelmail expects an empty file if no ispell dicts are installed.
if ( $class eq "ispell" ){
# Remove $old_ispell_default. Could be a symlink and target be written.
unlink "$old_ispell_default"; #
open (DEFAULT, "> $old_ispell_default");
print DEFAULT "";
close DEFAULT;
}
}
}
# ------------------------------------------------------------------
sub setuserdefault {
# ------------------------------------------------------------------
# Write user's default value to user's default file
# ------------------------------------------------------------------
my $default = getuserdefault ();
my $dictionaries = loaddb ("ispell");
my %languages = ();
my %elanguages = ();
foreach my $language ( sort keys %$dictionaries ){
my $entry = $dictionaries->{$language};
my $elanguage = $language;
if ( defined $entry->{'elanguage'} ){
$elanguage = $entry->{'elanguage'};
}
$languages{$elanguage} = $language;
$elanguages{$language} = $elanguage;
}
unless ( %languages ) {
warn "Sorry, no ispell dictionary is installed in your system.\n";
return;
}
my @choices = sort keys %languages;
my $initial = -1;
if ( defined $default ) {
my $default = $elanguages{$default};
for ( my $i = 0; $i < scalar @choices; $i++ ) {
if ( $default eq $choices[$i] ) {
$initial = $i;
last;
}
}
}
open (TTY, "/dev/tty");
while (1) {
$| = 1;
print
"\nSelect your personal ispell dictionary for use with ispell-wrapper\n\n";
for ( my $i = 0; $i < scalar @choices; $i++ ) {
print " " . ($i == $initial ? "*" : " ")
. " [" . ($i+1) . "] $choices[$i]\n";
}
print qq(\nSelect number or "q" for quit)
. ($initial != -1 ? " (* is the current default): " : ": ");
my $sel = <TTY>;
chomp $sel;
last if $sel eq "q";
if ($sel < 1 or $sel > scalar @choices) {
print qq{\nInvalid choice "$sel".\n\n};
next;
}
else {
$sel--;
open (DEFAULT, "> $userdefault");
print DEFAULT $languages{$choices[$sel]};
close DEFAULT;
last;
}
}
close TTY;
}
# ------------------------------------------------------------------
sub generate_comment {
# ------------------------------------------------------------------
# Generate a standard comment string with given prefix
# ------------------------------------------------------------------
my $commstr = shift;
my $comment = "This file is part of the dictionaries-common package.
It has been automatically generated.
DO NOT EDIT!";
$comment =~ s{^}{$commstr}mg;
return "$comment\n";
}
# ------------------------------------------------------------------
sub dico_find_matching_choice {
# ------------------------------------------------------------------
# Try a single regexp match from given class choices
# ------------------------------------------------------------------
my $dictionaries = shift;
my $regexp = shift;
my @found_matches = grep {/$regexp/} keys %$dictionaries;
unless (@found_matches ) {
dico_debugprint "Try harder with case-independent match";
@found_matches = grep {/$regexp/i} keys %$dictionaries;
}
if ( scalar @found_matches eq 1 ){
return $found_matches[0];
} else {
my $dict_list = join("\n",sort keys %$dictionaries);
if ( @found_matches ){
dico_debugprint "Multiple matches for \"$regexp\":\n"
. join("\n",sort @found_matches);
} else {
dico_debugprint "No matches found for \"$regexp\". Available dicts:\n$dict_list";
}
return;
}
}
# ------------------------------------------------------------------
sub build_emacsen_support {
# ------------------------------------------------------------------
# Put info from dicts info files into emacsen-ispell-dicts.el
# ------------------------------------------------------------------
my $elisp = '';
my @classes = ("aspell","hunspell","ispell");
my %entries = ();
my %class_locales = ();
foreach my $class ( @classes ){
my $dictionaries = loaddb ($class);
foreach my $k (keys %$dictionaries) {
my $lang = $dictionaries->{$k};
next if (exists $lang->{'emacs-display'}
&& $lang->{'emacs-display'} eq "no");
my $hashname = $lang->{"hash-name"};
my $casechars = exists $lang->{casechars} ?
$lang->{casechars} : "[a-zA-Z]";
my $notcasechars = exists $lang->{"not-casechars"} ?
$lang->{"not-casechars"} : "[^a-zA-Z]";
my $otherchars = exists $lang->{otherchars} ?
$lang->{otherchars} : "[']";
my $manyothercharsp = exists $lang->{"many-otherchars"} ?
($lang->{"many-otherchars"} eq "yes" ? "t" : "nil") : "nil";
my $ispellargs = exists $lang->{"ispell-args"} ?
$lang->{"ispell-args"} : "-d $hashname";
my $extendedcharactermode = exists $lang->{"extended-character-mode"} ?
('"' . $lang->{"extended-character-mode"} . '"') : "nil";
my $codingsystem = exists $lang->{"coding-system"} ?
$lang->{"coding-system"} : "nil";
my $emacsen_name = defined $lang->{"emacsen-name"} ?
$lang->{"emacsen-name"} : $hashname;
my $emacsen_names = defined $lang->{"emacsen-names"} ?
$lang->{"emacsen-names"} : $emacsen_name;
# Explicitly add " -d $hashname" to $ispellargs if not already there.
# Note that this must check for "-dxx", "-d xx", "-C -d xx", "-C -dxx" like matches
if ( $ispellargs !~ m/( |^)-d/ ){
dico_debugprint(" - $class-emacsen: Adding \" -d $hashname\" to \"$ispellargs\"");
$ispellargs .= " -d $hashname";
}
foreach my $emacsenname ( split(',\s*',$emacsen_names) ){
$entries{$class}{$emacsenname} = $entries{'all'}{$emacsenname} =
['"' . $emacsenname . '"',
'"' . $casechars . '"',
'"' . $notcasechars . '"',
'"' . $otherchars . '"',
$manyothercharsp,
'("' . join ('" "', split (/\s+/,$ispellargs)) . '")',
$extendedcharactermode,
$codingsystem];
if ( $class eq "aspell" && exists $lang->{"aspell-locales"} ){
foreach ( split(/\s*,\s*/,$lang->{"aspell-locales"}) ){
$class_locales{"aspell"}{$_} = $emacsenname;
}
} elsif ( $class eq "hunspell" && exists $lang->{"hunspell-locales"} ){
foreach ( split(/\s*,\s*/,$lang->{"hunspell-locales"}) ){
$class_locales{"hunspell"}{$_} = $emacsenname;
}
}
}
}
}
# Write alists of ispell, hunspell and aspell only installed dicts and their properties
foreach my $class ( @classes ) {
my @class_dicts = reverse sort keys %{ $entries{$class} };
if ( scalar @class_dicts ){
$elisp .= "\n;; Adding $class dicts\n\n";
foreach ( @class_dicts ){
my $mystring = join ("\n ",@{ $entries{$class}{$_} });
$elisp .= "(add-to-list \'debian-$class-only-dictionary-alist\n \'($mystring))\n";
}
$elisp .= "\n";
}
}
# Write a list of locales associated to each emacsen name
foreach my $class ("aspell", "hunspell"){
my $tmp_locales = $class_locales{$class};
if ( defined $tmp_locales && scalar %$tmp_locales ){
$elisp .= "\n\n;; An alist that will try to map $class locales to emacsen names";
$elisp .= "\n\n(setq debian-$class-equivs-alist \'(\n";
foreach ( sort keys %$tmp_locales ){
$elisp .= " (\"$_\" \"$tmp_locales->{$_}\")\n";
}
$elisp .= "))\n";
# Obtain here debian-aspell-dictionary, after debian-aspell-equivs-alist
# is loaded
$elisp .="
;; Get default value for debian-$class-dictionary. Will be used if
;; spellchecker is $class and ispell-local-dictionary is not set.
;; We need to get it here, after debian-$class-equivs-alist is loaded
(setq debian-$class-dictionary (debian-ispell-get-$class-default))\n\n";
} else {
$elisp .= "\n\n;; No emacsen-$class-equivs entries were found\n";
}}
open (ELISP, "> $cachedir/$emacsensupport")
or die "Cannot open emacsen cache file";
print ELISP generate_comment (";;; ");
print ELISP $elisp;
close ELISP;
}
# ------------------------------------------------------------------
sub build_jed_support {
# ------------------------------------------------------------------
# Put info from dicts info files into jed-ispell-dicts.sl
# ------------------------------------------------------------------
my @classes = ("aspell","ispell");
my $slang = generate_comment ("%%% ");
## The S-Lang code generated below will be wrapped in preprocessor
## ifexists constructs, insuring that the $jedsupport file will
## always evaluate correctly.
foreach my $class ( @classes ){
my %class_slang = ();
my %class_slang_u8 = ();
if ( my $dictionaries = loaddb ($class) ){
foreach my $k (sort keys %$dictionaries) {
my $lang = $dictionaries->{$k};
next if (exists $lang->{'jed-display'}
&& $lang->{'jed-display'} eq "no");
my $hashname = $lang->{"hash-name"};
my $additionalchars = exists $lang->{additionalchars} ?
$lang->{additionalchars} : "";
my $otherchars = exists $lang->{otherchars} ?
$lang->{otherchars} : "'";
my $emacsenname = exists $lang->{"emacsen-name"} ?
$lang->{"emacsen-name"} : $hashname;
my $extendedcharmode = exists $lang->{"extended-character-mode"} ?
$lang->{"extended-character-mode"} : "";
my $ispellargs = exists $lang->{"ispell-args"} ?
$lang->{"ispell-args"} : "";
my $codingsystem = exists $lang->{"coding-system"} ?
$lang->{"coding-system"} : "l1";
# Strip enclosing [] from $otherchars
$otherchars =~ s/^\[//;
$otherchars =~ s/\]$//;
# Convert chars in octal \xxx representation to the character
$otherchars =~ s/\\([0-3][0-7][0-7])/chr(oct($1))/ge;
$additionalchars =~ s/\\([0-3][0-7][0-7])/chr(oct($1))/ge;
$class_slang{$emacsenname} =
" $class" . "_add_dictionary (\n"
. " \"$emacsenname\",\n"
. " \"$hashname\",\n"
. " \"$additionalchars\",\n"
. " \"$otherchars\",\n"
. ($class eq "ispell" ? " \"$extendedcharmode\",\n" : "")
. " \"$ispellargs\");";
if ( $class eq "aspell" ){
my $converter = Text::Iconv->new ($codingsystem, "utf8");
my $additionalchars_utf = $converter->convert ($additionalchars);
my $otherchars_utf = $converter->convert ($otherchars);
$class_slang_u8{$emacsenname} =
qq{ aspell_add_dictionary (
"$emacsenname",
"$hashname",
"$additionalchars_utf",
"$otherchars_utf",
"$ispellargs");};
} # if $class ..
} # foreach $k ..
} # if loaddb ..
if ( scalar keys %class_slang ){
$slang .= "\n\#ifexists $class" . "_add_dictionary\n";
if ( $class eq "aspell" ){
$slang .= " if (_slang_utf8_ok) {\n"
. join("\n",sort values %class_slang_u8)
. "\n } else {\n"
. join("\n",sort values %class_slang)
. "\n }";
} else {
$slang .= join("\n",sort values %class_slang);
}
$slang .= "\n\#endif\n";
}
} # foreach $class
open (SLANG, "> $cachedir/$jedsupport")
or die "Cannot open jed cache file";
print SLANG $slang;
close SLANG;
}
# ------------------------------------------------------------------
sub build_squirrelmail_support {
# ------------------------------------------------------------------
# Build support file for squirrelmail with a list of available
# dictionaries and associated spellchecker calls, in php format.
# ------------------------------------------------------------------
my @classes = ("aspell","ispell","hunspell");
my $php = "<?php\n";
my @dictlist = ();
$php .= generate_comment ("### ");
$php .= "\$SQSPELL_APP = array (\n";
foreach my $class (@classes) {
my $dictionaries = loaddb ($class);
foreach ( keys %$dictionaries ){
next if m/.*[^a-z]tex[^a-z]/i; # Discard tex variants
my $lang = $dictionaries->{$_};
my $squirrelname;
if ( defined $lang->{"squirrelmail"} ){
next if ( lc($lang->{"squirrelmail"}) eq "no" );
$squirrelname = $lang->{"squirrelmail"};
} else {
next unless m/^(.*)\((.+)\)$/;
$squirrelname = $2;
}
my $spellchecker_params =
&dico_get_spellchecker_params($class,$lang);
push @dictlist, qq { '$squirrelname ($class)' => '$class -a $spellchecker_params'};
}
}
$php .= join(",\n", sort @dictlist);
$php .= "\n);\n";
open (PHP, "> $cachedir/$squirrelmailsupport")
or die "Cannot open SquirrelMail cache file";
print PHP $php;
close PHP;
}
# ------------------------------------------------------------------
sub dico_activate_trigger {
# ------------------------------------------------------------------
# Try activating provided trigger if run under dpkg control.
# Return true in success, nil otherwise.
# ------------------------------------------------------------------
my $trigger = shift;
my $options = shift;
my $await_trigger = defined $options->{'trigger-await'} ? "" : " --no-await ";
die "DictionariesCommon::dico_activate_trigger: No trigger provided. Aborting ...\n" unless $trigger;
if ( defined $ENV{'DPKG_RUNNING_VERSION'} &&
system("type dpkg-trigger >/dev/null 2>&1 && dpkg-trigger $await_trigger $trigger") == 0 ){
dico_debugprint("DictionariesCommon::dico_activate_trigger: Enabled trigger \"$trigger\" [$await_trigger]");
return 1;
}
return;
}
# ------------------------------------------------------------------
sub dico_clean_orphaned_removefiles {
# ------------------------------------------------------------------
# Clean orphaned remove files and their contents.
#
# dico_clean_orphaned_removefiles($class,$dictionaries)
# ------------------------------------------------------------------
my $class = shift;
die "DictionariesCommon::dico_preprocess_default_symlinks: No class passed"
unless $class;
my $dictionaries = shift;
die "DictionariesCommon::dico_preprocess_default_symlinks: No dictionaries passed"
unless $dictionaries;
my $program = "update-default-$class";
my $varlibdir = "/var/lib/$class";
return unless ( $class eq "aspell" or $class eq "ispell" );
foreach my $remove_file (<$varlibdir/*.remove>){
my $dict = $remove_file;
$dict =~ s/\.remove$//;
$dict =~ s/.*\///;
my $compat_file = "$varlibdir/$dict.compat";
# Remove orphaned remove files and its contents if no matching .compat file is found
unless ( -e "$compat_file" ){
open (my $REMOVE,"$remove_file");
while (<$REMOVE>){
chomp;
next if m/^\s*$/;
if ( -e "$_"
&& m:^(/usr/lib|/var/lib): ){
unlink "$_";
print STDERR "$program: Removing \"$_\".\n";
}
}
close $REMOVE;
unlink "$remove_file";
print STDERR "$program: Removing remove file \"$remove_file\".\n";
}
}
# Remove $varlibdir directory if empty and not owned
if ( -d "$varlibdir" ){
unless ( scalar <"$varlibdir/*"> ){
if ( system("dpkg-query -S $varlibdir > /dev/null 2>&1") == 0 ){
dico_debugprint("$program: Empty \"$varlibdir\" is owned by some package.");
} elsif ( scalar %$dictionaries ){
print STDERR "$program: Empty and unowned \"$varlibdir\", but \"$class\" elements installed.\n";
} else {
rmdir "$varlibdir";
print STDERR "$program: Removing unowned and empty \"$varlibdir\" directory.\n";
}
}
}
}
# ------------------------------------------------------------------
sub dico_preprocess_default_symlinks {
# ------------------------------------------------------------------
# Set default symlinks at $libdir if needed. Remove default symlinks
# at $libdir and $etcdir unless they are not dangling
#
# dico_preprocess_default_symlinks ($class,$dictionaries)
# ------------------------------------------------------------------
my $class = shift;
die "DictionariesCommon::dico_preprocess_default_symlinks: No class passed"
unless $class;
my $dictionaries = shift;
die "DictionariesCommon::dico_preprocess_default_symlinks: No dictionaries passed"
unless $dictionaries;
my $program = "installdeb-$class";
my $linkdir = "/etc/dictionaries-common";
my $libdir = { 'ispell' => "/usr/lib/ispell",
'wordlist' => "/usr/share/dict"};
my $links = {'ispell' => ["default.hash", "default.aff"],
'wordlist' => ["words"]};
if ( %{$dictionaries} ){
foreach my $link ( @{$links->{$class}} ){
my $link_from = "$libdir->{$class}/$link";
unless ( -e "$link_from" ){
if ( -w "$libdir->{$class}" ){
print STDERR "Symlinking $link_from to $linkdir/$link\n"
if $debug;
symlink "$linkdir/$link","$link_from";
} else {
print STDERR "$program:Warning: Non writable \"$libdir->{$class}\" dir. Read-only filesystem?\n";
}
}
}
} else {
foreach my $link ( @{$links->{$class}} ){
my $default_etc_link = "$linkdir/$link";
my $default_usr_link = "$libdir->{$class}/$link";
foreach my $default_link ( "$default_etc_link","$default_usr_link"){
if ( -l "$default_link" ){
if ( -e readlink "$default_link" ){ # Non-dangling symlink
print STDERR "$program: Leaving non dangling symlink behind: \"$default_link\"\n";
} else {
if ( -w "$libdir->{$class}" ){
dico_debugprint("No $class elements. Remove $default_link.");
unlink "$default_link"
} else {
print STDERR "$program:Warning: Non writable \"$libdir->{$class}\" dir. Read-only filesystem?\n";
}
}
} elsif ( -e "$default_link" ){
print STDERR "Leaving non symlink \"$default_link\" behind.\n"
}
}
}
}
}
# ------------------------------------------------------------------
sub dico_set_default_symlink {
# ------------------------------------------------------------------
# Try setting default symlinks for ispell dictionaries and wordlists.
# dico_set_default_symlink($class,$value)
# ------------------------------------------------------------------
my $class = shift;
die "DictionariesCommon::dico_set_default_symlink: No class passed" unless $class;
my $value = shift;
die "DictionariesCommon::dico_set_default_symlink: No value passed" unless $value;
my $dictionaries = loaddb ($class);
my $program = "update-default-$class";
my $linkdir = "/etc/dictionaries-common";
my $class_name = { 'ispell' => "ispell dictionary",
'wordlist' => "wordlist"};
my $libdir = { 'ispell' => "/usr/lib/ispell",
'wordlist' => "/usr/share/dict"};
my $link_suffixes = { 'ispell' => [".hash", ".aff"],
'wordlist' => [""]};
my $link_basename = { 'ispell' => "default",
'wordlist' => "words"};
if ( defined $dictionaries->{$value}{"hash-name"} ){
dico_debugprint("update-default-$class: \"$value\" -> \"$dictionaries->{$value}{'hash-name'}\"");
my $hash = "$libdir->{$class}/" . $dictionaries->{$value}{"hash-name"};
foreach my $i ( @{$link_suffixes->{$class}}) {
my $link_to = "$hash$i";
if ( -e "$link_to" ) {
my $link_from = "$linkdir/$link_basename->{$class}$i";
system "ln -fs $link_to $link_from";
dico_debugprint("$program: \"$link_from\" symlink set to \"$link_to\"");
} else {
die "$program:
Could not make the default symlink to \"$link_to\".
This may be a temporary problem due to installation ordering. If that
file is not present after installation, please file a bugreport
against $class_name->{$class} package owning that file.
\n";
}
}
} else {
die "$program: Selected value \"$value\" for $class_name->{$class}\n" .
"does not contain a hash name entry in the database.\n";
}
}
# Ensure we evaluate to true.
1;
__END__
#Local Variables:
#perl-indent-level: 2
#End:
=head1 NAME
Debian::DictionariesCommon.pm - dictionaries-common library
=head1 SYNOPSIS
use Debian::DictionariesCommon q(:all)
$dictionaries = parseinfo ('/var/lib/dictionaries-common/ispell/iwolof');
loaddb ('ispell')
updatedb ('wordlist')
=head1 DESCRIPTION
Common functions for use from the dictionaries-common system.
=head1 CALLING FUNCTIONS
=over
=item C<dico_checkroot>
Check for rootness and fail if not.
=item C<build_emacsen_support>
Put info from dicts info files into emacsen-ispell-dicts.el
=item C<build_jed_support>
Put info from dicts info files into jed-ispell-dicts.sl
=item C<build_squirrelmail_support>
Build support file for squirrelmail with a list of available
dictionaries and associated spellchecker calls, in php format.
=item C<$libdir = getlibdir($class)>
Return info dir for given class.
=item C<$default = dico_getsysdefault($class)>
Return system default value for given class.
=item C<$libdir = getuserdefault>
Return value for user default ispell dictionary.
=item C<dico_get_spellchecker_params($class,\%language)>
Get right params for $class (currently unused) and $language
=item C<\%dictionaries = loaddb($class)>
Read class .db file and return a reference to a hash
with its contents.
=item C<\%result = parseinfo($file)>
Parse given info file and return a reference to a hash with
the relevant data.
=item C<setsysdefault($value)>
Set value for system default ispell dictionary.
=item C<setuserdefault>
Set value for user default ispell dictionary, after asking
to select it from the available values.
=item C<updatedb($class)>
Parse info files for given class and update class .db
file under dictionaries-common cache dir.
=back
=head1 SEE ALSO
Debian dictionaries-common policy.
=head1 AUTHORS
Rafael Laboissiere
Agustin Martin
=cut