summaryrefslogtreecommitdiffstats
path: root/scripts/extractattr
blob: 324b1f56b8d166328d221bfaa8959b8a8ed218d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#! /usr/bin/env perl

#
# Copyright (c) 2004 Richard Evans <rich@ridas.com>
#
# License: LGPL 2.0
#

sub usage
{
  warn <<"EOF";

extractattr [flags] filenames

This script extracts element attributes from designer (.ui) and XMLGIU (.rc) files
and writes on standard output (usually redirected to rc.cpp) the equivalent
i18n() calls so that xgettext can parse them.

--attr=spec    : Specify the attribute to be extracted. The specification
                 consists of the following comma separated arguments:

                 Element,attribute[,context]

                 The context is optional and overrides the name set by
                 --context below. Repeat the flag to specify multiple
                 attributes:

                 --attr=Title,data --attr=Description,data,Stencils

--context=name : Give i18n calls a context name: i18n("name", ...)
--lines        : Include source line numbers in comments (deprecated, it is switched on by default now)
--help|?       : Display this summary

EOF

  exit;
}

###########################################################################################

use strict;
use warnings;
use Getopt::Long;

###########################################################################################
# Add options here as necessary - perldoc Getopt::Long for details on GetOptions

GetOptions ( "attr=s"    => \my @opt_attr,
             "context=s" => \my $opt_context,
             "lines"     => \my $opt_lines,
             "help|?"    => \&usage );

unless ( @ARGV )
{
  warn "No filename specified";
  exit;
}

unless ( @opt_attr )
{
  warn "No attributes specified";
  exit;
}

###########################################################################################
# Program start proper - NB $. is the current line number

my $code =<<'EOF';
our $file_name;

for $file_name ( @ARGV )
{
  my $fh;

  unless ( open $fh, "<", $file_name )
  {
    warn "Failed to open: '$file_name': $!";
    next;
  }

  while ( <$fh> )
  {
    last if $. == 1 and $_ !~ /^(?:<!DOCTYPE|<\?xml)/;
EOF

$code .= build_code(@opt_attr) . <<'EOF';
  }

  close $fh or warn "Failed to close: '$file_name': $!";
}

1;
EOF

# warn "CODE TO EVAL:\n$code\n";
  
eval $code or die;


sub build_code
{
  my $code = "\n";

  my %seen;

  for ( @_ )
  {
    my ($element, $attribute, $context) = ((split /,/), "", "", "");

    length $element   or die "Missing element in --attr=$_";
    length $attribute or die "Missing attribute in --attr=$_";

    if ( $seen{$element . '<' . $attribute}++ )
    {
      warn "Skipping duplicate flag --attr=$_ (element/attribute pair has already been specified)";
      next;
    }

    $code .= "    /<" . quotemeta($element)   . qq| [^>]*?| .
                        quotemeta($attribute) . qq|="([^"]+)"/ and write_i18n('| . $context . qq|', \$1);\n|;
  }

  return "$code\n";
}

sub write_i18n
{
  my ($context, $text) = @_;

  our $file_name;

  unless ( $text )
  {
    print "// Skipped empty message at $file_name line $.\n";
    return;
  }

  $text =~ s/&lt;/</g;
  $text =~ s/&gt;/>/g;
  $text =~ s/&apos;/\'/g;
  $text =~ s/&quot;/\"/g;
  $text =~ s/&amp;/&/g;

  # Escape characters exactly like uic does it
  # (As extractrc needs it, we follow the same rule to avoid to be different.)
  $text =~ s/\\/\\\\/g; # escape \
  $text =~ s/\"/\\\"/g; # escape "
  $text =~ s/\r//g; # remove CR (Carriage Return)
  $text =~ s/\n/\\n\"\n\"/g; # escape LF (Line Feed). uic also change the code line at a LF, we do not do that.
  
  $context ||= $opt_context;

  print "//i18n: file $file_name line $.\n";
  print qq|i18n("|;
  print qq|$context", "|            if $context;
  print qq|$text");\n|;
}