#!/usr/bin/perl -w # /*=========================================================================* # * Title : BibTeX Database Generator (Interactive script) # * File : bibtex.pl # * # * Author : Pallav Gupta # * Created : Sat Aug 23 20:36:59 2003 # * # * This source code can be redistributed under the GNU Free Public Licence. # *=========================================================================*/ # /* $Id: bibtex.pl,v 1.4 2003/10/09 04:04:27 pgupta Exp $ */ # Usage: bibtex.pl require Term::ReadKey; require Term::ANSIColor; require File::Basename; use File::Basename; use Term::ReadKey; use Term::ANSIColor qw(:constants); use strict; # Contains template for the bibtex entries my $program_dir = dirname($0); my $template = "$program_dir/bibtex.template"; # Global variables # Interactive prompt my $prompt = "bibtex>"; # Map each of the entries to its shortcut command my %types; # Hash table to store all the entries my %entries; # Main program &bibtex_header(*STDOUT); &bibtex_initialize_structures(); &exec_bibtex_script(*STDIN); exit 0; # Options interpreter sub exec_bibtex_script { my $fp = shift @_; print "\nType 'h(elp)' for help message.\n"; print "\n$prompt"; while(<$fp>) { chomp($_); if (/^$/ || /^\#/) { next; } if (/^q(uit)?/) { last; } elsif (/^c(reate)?\s+(\w+)/) { &bibtex_new_entry($2); } elsif (/^h(elp)?/) { &bibtex_help(); } elsif (/^s(how)?\s*(.*)?/) { &bibtex_show_entry(*STDOUT, $2); } elsif (/^d(del)?\s*(.*)?/) { &bibtex_del_entry($2); } elsif (/^m(odify)?\s+(.*)/) { &bibtex_modify_entry($2); } elsif (/^k(eys)?/) { &bibtex_show_keys(); } elsif (/^w(rite)?\s+(.*)/) { &bibtex_write_to_file(0,$2); # 0 is for no appending } elsif (/^a(append)?\s+(.*)/) { &bibtex_write_to_file(1,$2); # 1 is for appending } else { &bibtex_error("Invalid option '$_'. Type 'h(elp)' for help message."); } print "\n$prompt"; } } # Here we initialize the fields each type of bibtex entry must have sub bibtex_initialize_structures { die "File $template does not exist. Aborting $0." if (!-e "$template"); open(IN, "$template") || die "Unable to open file $template"; print "Reading $template and initializing ...\n"; while () { chomp $_; next if ($_ eq ''); # ignore comments that begin with # m/^\#|^\s/ and do { next; }; m/(.*);\s*(.*);\s*(.*)/ and do { my $type = $1; my $symb = $3; $type =~ s/\s//g; $symb =~ s/\s//g; my @fields = split /,\s+/,$2; unshift @fields, $type; print "Read $symb : @fields\n"; $types{$symb} = \@fields; next; }; die "Parse error: unable to parse '$_'\n"; } close(IN); } # Create a new entry of type 'type' sub bibtex_new_entry { my $type = shift @_; my @entry; my %data; if (!exists $types{$type}) { bibtex_error("I don't know how to process entry of type '$type'."); return; } @entry = @{$types{$type}}; my $char = &bibtex_readchar("Create entry type '$entry[0]'"); return if ($char eq 'n'); $data{"type"} = $type; for (my $i = 1; $i <= $#entry; $i++) { print "$entry[$i]>"; my $line = ; chomp($line); $data{$entry[$i]} = $line; } print "key>"; my $key = ; chomp($key); $key =~ s/\s//g; while (1) { if (exists $entries{$key}) { print "An entry with key '$key' already exists. Enter new key>"; } elsif ($key eq "") { print "Invalid key '$key'. Enter new key>"; } else { last; } $key = ; chomp($key); $key =~ s/\s//g; } $entries{$key} = \%data; } # Displays the key of each entry in database sub bibtex_show_keys { if (scalar keys %entries == 0) { &bibtex_error("There are no entries."); return; } my $i = 0; foreach my $key (keys %entries) { print "$key"; if (($i++)%5 == 0) { print "\n"; } else { print ", "; } } } # Modify an entry with key 'key' sub bibtex_modify_entry { my $key = shift @_; if (scalar keys %entries == 0) { &bibtex_error("There are no entries."); return; } if (defined $key && $key ne "") { chomp ($key); if (!exists $entries{$key}) { &bibtex_error("No entry found with key $key"); return; } else { my %data = %{$entries{$key}}; my @fields = @{$types{$data{"type"}}}; print "\nModifying entry '$fields[0]'. To keep old value of a field, press \n"; for (my $i = 1; $i <= $#fields; $i++) { print "$fields[$i]: ", RED, "$data{$fields[$i]}\n", RESET; print "Enter new value>"; my $str = ; chomp($str); if ($str ne "") { $data{$fields[$i]} = $str; } } $entries{$key} = \%data; } print "\n"; } else { &bibtex_error("No key supplied. Aborted!"); return; } } # Display all or a single entry sub bibtex_show_entry { my ($fh, $key) = (@_); if (scalar keys %entries == 0) { &bibtex_error("There are no entries."); return; } if (defined $key && $key ne "") { chomp($key); if (exists $entries{$key}) { &bibtex_print_entry($fh, $key); } else { &bibtex_error("No entry found with key $key"); return; } } else { foreach $key (sort keys %entries) { &bibtex_print_entry($fh, $key); } } } # Delete an entry with key 'key' sub bibtex_del_entry { my $key = shift @_; if (scalar keys %entries == 0) { &bibtex_error("There are no entries."); return; } if (defined $key && $key ne "") { chomp ($key); if (exists $entries{$key}) { delete $entries{$key}; } else { &bibtex_error("No entry found with key $key"); return; } } else { my $char = &bibtex_readchar("Delete all entries"); return if ($char eq 'n'); %entries = (); } } # Print an entry with key 'key' sub bibtex_print_entry { my ($fh, $key) = (@_); my %entry_data = %{$entries{$key}}; my @entry_type = @{$types{$entry_data{"type"}}}; print $fh "\n\@$entry_type[0]\{$key,\n"; for (my $i = 1; $i <= $#entry_type; $i++) { print $fh "$entry_type[$i] = \{$entry_data{$entry_type[$i]}\}"; print $fh ",\n" if ($i != $#entry_type); } print $fh "\n};\n"; } # Write bibtex to file sub bibtex_write_to_file { my ($append, $file) = (@_); if (not defined $file || $file eq "") { &bibtex_error("Invalid name '$file' for file specified"); return; } if (scalar keys %entries == 0) { &bibtex_error("There are no entries."); return; } my $t; if ($append) { $t = ">>$file"; } else { $t = ">$file"; } if (!open(OUT, $t)) { &bibtex_error("Unable to open $file for writing. Aborted!"); return; } &bibtex_show_entry(*OUT, ""); close(OUT); } # Help msg sub bibtex_help { print "\nCommands that are currently supported:\n"; print CYAN, "h(elp)", RESET, "\t\t\t - this help\n"; print CYAN, "c(reate) "; my @keys = sort keys %types; print "["; for (my $i = 0; $i < $#keys; $i++) { print "$keys[$i]|"; } print "$keys[$#keys]]", RESET, " - create an entry type\n"; foreach my $i (@keys) { print RED "\t $i", RESET, "\t: @{$types{$i}}[0]\n"; } print CYAN, "d(el) []", RESET, "\t\t - delete bibtex entry with key \n"; print "\t\t\t NOTE: not supplying a key will delete everything!\n"; print CYAN, "s(how) []", RESET, "\t\t - show bibtex entry with key \n"; print "\t\t\t NOTE: not supplying a key will show everything!\n"; print CYAN, "m(odify) ", RESET, "\t\t - modify values of entry with key \n"; print CYAN, "w(rite) ", RESET, "\t\t - write bibtex database to file by sorting keys\n"; print CYAN, "a(ppend) ", RESET, "\t\t - append bibtex database to file by sorting keys\n"; print CYAN, "k(eys)", RESET, "\t\t\t - show all keys in current database\n"; print CYAN, "q(uit)", RESET, "\t\t\t - quit\n"; } # Print error messages sub bibtex_error { my @msgs = (@_); foreach my $msg (@msgs) { print "\nERROR: $msg\n"; } } # Read a char from stdin sub bibtex_readchar { my $msg = shift @_; my $char = 'g'; ReadMode('cbreak'); while (!($char eq 'y' || $char eq 'n')) { print "\n$msg [y|n]?"; $char = ReadKey(0); } ReadMode('normal'); print "\n"; return $char; } # Script header info sub bibtex_header { my $fh = shift @_; my $prog_name = "BibTeX Database Generator"; my $email = "pallav\@ieee.org"; my $author = "Pallav Gupta"; my $version = "1.0"; my $date = `date`; print $fh "Starting $prog_name \t\t $date\n"; print $fh "Author: $author\n"; print $fh "Version: $version\n"; print $fh "Report bugs: $email\n"; }