archer-master -> gdb-master
[nethome.git] / bin / xbelnormalize
1 #! /usr/bin/perl
2 #
3 # $Id$
4 #
5 # Normalize the .xbel file for cvs(1)/diff(1) etc.
6 # Removes any variable data from the file.
7 # Reencodes the file to utf-8.
8 #
9 # Copyright (C) 2005 Jan Kratochvil <project-xbelnormalize@jankratochvil.net>
10
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; exactly version 2 of June 1991 is required
14
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24
25 use strict;
26 use warnings;
27
28 require XML::Twig;
29 use File::Temp qw(tempfile);
30
31
32 my $opt_replace;
33 # No &Getopt::Long::GetOptions as we need to distinguish '-i' and '-iext'.
34 while (@ARGV) {
35         last if $ARGV[0]!~/^-/;
36         local $_=shift @ARGV;
37         if ($_ eq "-h" || $_ eq "--help") {
38                 print <<"HERE";
39 @{[ '$Id$' ]}
40
41 Syntax: $0 [-i[<extension>]] [<file.xbel>]
42
43 -i[<extension>] edit the file in place (makes backup if extension supplied)
44 HERE
45                 exit;
46         }
47         if (s/^-i//) {
48                 $opt_replace=$_;
49                 next;
50         }
51         if ($_ eq "--") {
52                 last;
53         }
54         die "Invalid argument: $_\n";
55 }
56 die "Too many files\n" if 1<@ARGV;
57
58 my $twig=XML::Twig->new(
59         "pretty_print"=>"indented",
60         "output_encoding"=>"utf-8",
61         "ignore_elts"=>{
62                 "time_visited"=>1,
63                 "time_added"=>1,
64                 "time_modified"=>1,
65                 "smart_site_data"=>1,
66         },
67         "twig_roots"=>{
68                 "metadata"=>sub { $_->delete() if !$_->has_children(); },
69                 "info"    =>sub { $_->delete() if !$_->has_children(); },
70                 "folder"=>sub { $_->del_att("folded"); },
71                 "xbel"  =>sub { $_->del_att("folded"); },
72         },
73 );
74 my $filename;
75 if (!($filename=$ARGV[0])) {
76         $twig->parse(\*STDIN);
77         $twig->flush();
78         exit;
79 }
80 $twig->parsefile($filename);
81 my $tmpname;
82 my $dstfh;
83 if (!defined $opt_replace) {
84         $dstfh=\*STDOUT;
85 } else {
86         if (!$opt_replace) {
87                 (undef(),$tmpname)=tempfile("DIR"=>".");
88         } elsif ($opt_replace=~/[*]/) {
89                 ($tmpname=$opt_replace)=~s/[*]/$filename/g;
90         } else {
91                 $tmpname=$filename.$opt_replace;
92         }
93         rename($filename,$tmpname) or die "Error renaming \"$filename\" to \"$tmpname\": $!";
94         open $dstfh,">",$filename or die "Error opening target file \"$filename\": $!";
95 }
96 $twig->flush($dstfh);
97 if (defined $opt_replace) {
98         close $dstfh or die "Error closing target file \"$filename\": $!";
99         if (!$opt_replace) {
100                 unlink $tmpname or die "Error deleting temporary file \"$tmpname\": $!";
101         }
102 }