+main();
+
+sub main{
+
+ my $dbh;
+ my $sth;
+ if (exists $options{bibtex_cache}) {
+ my $initialize = 0;
+ if (-e $options{bibtex_cache}) {
+ ($dbh,$sth) = open_cache($options{bibtex_cache});
+ } else {
+ ($dbh,$sth) = initialize_database($options{bibtex_cache});
+ }
+ }
+
+ if (exists $options{clear_cache}) {
+ clear_cache($dbh,$sth);
+ }
+ my %entries;
+ if (exists $options{build_cache}) {
+ $options{bibtex} //= [];
+ $options{bibtex} =
+ [@ARGV,
+ @{ref $options{bibtex}?$options{bibtex}:[$options{bibtex}]},
+ ];
+ @ARGV = ();
+ }
+ if (exists $options{bibtex}) {
+ for my $bibtex_file (@{ref $options{bibtex}?$options{bibtex}:[$options{bibtex}]}) {
+ parse_bibtex_file($bibtex_file,\%entries);
+ }
+ }
+
+ if (exists $options{papers_directory} and
+ defined $dbh
+ ) {
+ $dbh->begin_work;
+ load_papers_into_database($dbh,$sth,$options{papers_directory});
+ $dbh->commit;
+ }
+
+ p %entries if $DEBUG;
+ if (keys %entries and
+ defined $dbh) {
+ $dbh->begin_work;
+ load_bibtex_entries_into_database($dbh,$sth,\%entries);
+ $dbh->commit;
+ }
+
+ p @ARGV if $DEBUG;
+ for my $bibtex_key (@ARGV) {
+ open_bibtex_key(\%options,$dbh,$sth,\%entries,$bibtex_key);
+ }
+
+}
+
+sub clear_cache {
+ my ($dbh,$sth) = @_;
+ $sth->{clear_papers_cache}->execute();
+ $sth->{clear_bibtex_cache}->execute();
+}
+
+sub load_papers_into_database {
+ my ($dbh,$sth,$dir) = @_;
+
+ my @dirs = ref($dir)?@{$dir}:$dir;
+
+ if ($options{use_git}) {
+ my @files = grep /\.pdf\"?$/, split /\n/, qx(git ls-tree HEAD -r --full-name --name-only);
+ for my $file (@files) {
+ $file =~ s/^\"(.+)\"$/"qq($1)"/gee;
+ insert_or_replace_papers($dbh,$sth,basename($file),File::Spec->rel2abs($file), -e "${file}.xoj");
+ }
+ } else {
+ my $actually_load_it = sub {
+ if (/\.git/) {
+ $File::Find::prune = 1;
+ return;
+ }
+ return unless /\.pdf$/;
+ my $xoj = 0;
+ if (-e "${_}.xoj") {
+ $xoj = 1;
+ }
+ insert_or_replace_papers($dbh,$sth,basename($File::Find::name),File::Spec->rel2abs($_),$xoj);
+ };
+ find($actually_load_it,@dirs);
+ }
+}
+
+sub insert_or_replace_papers {
+ my ($dbh,$sth,$file_name,$file_loc,$has_xoj) = @_;
+ $sth->{insert_papers}->execute($file_name,$file_loc,$has_xoj);
+ $sth->{insert_papers}->finish();
+}
+
+sub load_bibtex_entries_into_database {
+ my ($dbh,$sth,$entries) = @_;
+ for my $entry (keys %{$entries}) {
+ next unless defined $entries->{$entry};
+ $sth->{insert_bibtex}->execute($entry,@{$entries->{$entry}}{qw(file_name pmid doi html)});
+ $sth->{insert_bibtex}->finish();
+ print STDERR "inserted $entry {".join(',',map {defined $_?"'$_'":"'undef'"} %{$entries->{$entry}})."}\n" if $DEBUG;
+ }
+}
+
+sub open_bibtex_key {
+ my ($options,$dbh,$sth,$entries,$bibtex_key) = @_;
+ if (not defined $dbh) {
+ open_entry($dbh,$sth,$entries->{$bibtex_key},$options);
+ } else {
+ my $entry;
+ if ($options->{search_by_pmid}) {
+ $entry = select_entry_from_pmid($dbh,$sth,$bibtex_key);
+ } elsif ($options->{search_by_file}) {
+ $entry = select_entry_from_file($dbh,$sth,$bibtex_key);
+ } else {
+ $entry = select_entry_from_bibtex_key($dbh,$sth,$bibtex_key);
+ }
+ p $entry if $DEBUG;
+ open_entry($dbh,$sth,$entry,$options);
+ }
+}
+
+sub fork_exec {
+ my (@cmd) = @_;
+ my $child = fork();
+ if (not defined $child) {
+ die "Unable to fork for some reason: $!";
+ }
+ if ($child == 0) {
+ foreach (0 .. (POSIX::sysconf (&POSIX::_SC_OPEN_MAX) || 1024))
+ { POSIX::close $_ }
+ open (STDIN, "</dev/null");
+ open (STDOUT, ">/dev/null");
+ open (STDERR, ">&STDOUT");
+ exec(@cmd);
+ } else {
+ return $child;
+ }
+
+}
+
+sub open_pdf {
+ my ($file_name,$options,$has_xoj) = @_;
+ print STDERR "opening $file_name\n" if $DEBUG;
+ my $pdf_viewer = 'xournal';
+ if (exists $options->{pdfviewer} and defined $options->{pdfviewer}) {
+ $pdf_viewer = $options->{pdfviewer};
+ }
+ fork_exec($pdf_viewer,$file_name);
+}
+
+sub open_browser{
+ my ($file) = @_;
+ fork_exec('sensible-browser',$file);
+}
+
+sub open_entry{
+ my ($dbh,$sth,$entry,$options) = @_;
+
+ return unless defined $entry and ref $entry and keys %{$entry};
+ if ($DEBUG) {
+ print STDERR "Entry: \n";
+ p $entry;
+ }
+ if (defined $entry->{file_name} and length $entry->{file_name}) {
+ my $paper = select_one($dbh,$sth->{select_papers_by_name},$entry->{file_name});
+ if (not defined $paper) {
+ my ($pmid) = $entry->{file_name} =~ /pmid_(\d+)/;
+ if (defined $pmid and length $pmid) {
+ $paper = select_one($dbh,$sth->{select_papers_by_pmid},'%pmid_'.$pmid.'.%');
+ }
+ }
+ p $paper if $DEBUG;
+ print STDERR $entry->{file_name} if $DEBUG;
+ if (defined $paper) {
+ if ($options->{only_print}) {
+ print $paper->{path};
+ return;
+ }
+ open_pdf($paper->{path},$options,$paper->{has_xoj});
+ return;
+ } else {
+ print STDERR "Unable to find paper\n" if $DEBUG;
+ }
+ }
+ if (defined $entry->{doi}) {
+ if ($options->{only_print}) {
+ print $entry->{doi};
+ return;
+ }
+ my $url = $entry->{doi};
+ $url =~ s{^doi://}{http://dx.doi.org/};
+ open_browser($url,$options);
+ return;
+ }
+ if (defined $entry->{html}) {
+ if ($options->{only_print}) {
+ print $entry->{html};
+ return;
+ }
+ open_browser($entry->{html},$options);
+ return;
+ }
+}
+
+sub select_entry_from_pmid{
+ my ($dbh,$sth,$pmid) = @_;
+
+ return select_one($dbh,$sth->{select_bibtex_by_pmid},$pmid);
+}
+
+sub select_entry_from_file{
+ my ($dbh,$sth,$filename) = @_;
+
+ return select_one($dbh,$sth->{select_bibtex_by_file_name_like},'%'.$filename.'%');
+}
+
+
+sub select_entry_from_bibtex_key{
+ my ($dbh,$sth,$bibtex_key) = @_;
+
+ my $entry = select_one($dbh,$sth->{select_bibtex_by_key},$bibtex_key);
+ if (not defined $entry) {
+ print STDERR "Unable to find entry by exact search\n" if $DEBUG;
+ $bibtex_key =~ s/:.*$//;
+ $entry = select_one($dbh,$sth->{select_bibtex_by_approximate_key},$bibtex_key.'%');
+ }
+ print STDERR "Found entry\n" if $DEBUG and defined $entry;
+ return $entry;
+}
+
+sub select_one{
+ my ($dbh,$sth,@bind_vals) = @_;
+ $sth->execute(@bind_vals) or
+ die "Unable to select one: ".$dbh->errstr();
+ my $results = $sth->fetchall_arrayref({});
+ $sth->finish();
+ return ref($results)?$results->[0]:undef;
+}
+