13 @EXPORT = qw(initLyxStack checkLyxLine closeLyxStack diestack);
17 sub initLyxStack($$$);
22 sub checkForEndBlock($);
29 sub checkForHeader($);
30 sub checkForPreamble($);
31 sub checkForLayoutStart($);
32 sub checkForInsetStart($);
33 sub checkForLatexCommand($);
36 my @stack = (); # list of HASH-Arrays
38 my $useNonTexFont = "true";
39 my $inputEncoding = undef;
42 # type (layout, inset, header, preamble, ...)
44 # matching list of matching spes
45 # search: regular expression
46 # ext: list of extensions needed for the full path of the file spec
47 # filetype: one of prefix_only,replace_only,copy_only,prefix_for_list,interpret
48 # fileidx: index into the resulting array, defining the filename
49 # result: conatenation of the elements should reflect the parsed line
50 # but first set the modified value into $result->[$fileidx]
51 # numerical value will be replaced with appropriate matching group value
56 if ($_[1] eq "systemF") {
57 $useNonTexFont = "true";
60 $useNonTexFont = "false";
61 $inputEncoding = $_[2];
63 $stack[0] = { type => "Starting"};
70 print "Called stack\n";
72 for my $depth ( 0 .. 100) {
73 #my ($pkg, $file, $line, $subname, $hasargs, $wantarray) = caller($depth)
74 my @stack = caller($depth);
75 last if ($stack[0] ne "main");
76 push(@call_stack, \@stack);
78 for my $depth ( 0 .. 100) {
79 last if (! defined($call_stack[$depth]));
80 my $subname = $call_stack[$depth]->[3];
81 my $line = $call_stack[$depth]->[2];
82 print "($depth) $subname()";
84 my $oldline = $call_stack[$depth-1]->[2];
87 print " called from ";
88 if (defined($call_stack[$depth+1])) {
89 my $parent = $call_stack[$depth+1]->[3];
90 print "$parent():$line\n";
93 my $file = $call_stack[$depth]->[1];
94 print "\"$file\":$line\n";
102 diestack("Stack not OK") if ($stack[0]->{type} ne "Starting");
109 $stack[0]->{"matching"} = $match;
114 return($stack[0]->{"matching"});
117 ###########################################################
119 sub checkForEndBlock($)
123 for my $et ( qw( layout inset preamble header)) {
124 if ($l =~ /^\\end_$et$/) {
125 diestack("Not in $et") if ($stack[0]->{type} ne "$et");
138 if (! defined($elem{"ext"})) {
141 if (! defined($elem{"filetype"})) {
142 $elem{"filetype"} = "prefix_only";
144 if (! defined($elem{"fileidx"})) {
145 $elem{"fileidx"} = 1;
147 diestack("No result defined") if (! defined($elem{"result"}));
155 return($m->{"search"});
162 return($m->{"filetype"});
169 return($m->{"fileidx"});
183 return($m->{"result"});
186 sub checkForHeader($)
190 if ($l =~ /^\\begin_header\s*$/) {
192 $selem{type} = "header";
194 unshift(@stack, \%selem);
196 $rElems[0] = newMatch("search" => '^\\\\master\s+(.*\.lyx)',
197 "filetype" => "prefix_only",
198 "result" => ["\\master ", ""]);
199 if (keys %{$rFont}) {
200 for my $ff ( keys %{$rFont}) {
201 # fontentry of type '\font_roman default'
202 my $elem = newMatch("search" => '^\\\\font_' . $ff . '\s+[^"]*\s*$',
203 "filetype" => "replace_only",
204 "result" => ["\\font_$ff ", $rFont->{$ff}]);
205 # fontentry of type '\font_roman "default"'
206 my $elem1 = newMatch("search" => '^\\\\font_' . $ff . '\s+"[^"]*"\s*$',
207 "filetype" => "replace_only",
208 "result" => ["\\font_$ff \"", $rFont->{$ff}, '"']);
209 # fontentry of type '\font_roman "default" "default"'
210 my $elem2 = newMatch("search" => '^\\\\font_' . $ff . '\s+"(.*)"\s+"(.*)"\s*$',
211 "filetype" => "replace_only",
212 "result" => ["\\font_$ff ", '"', "1", '" "', $rFont->{$ff}, '"']);
213 push(@rElems, $elem, $elem1, $elem2);
216 my $elemntf = newMatch("search" => '^\\\\use_non_tex_fonts\s+(false|true)',
217 "filetype" => "replace_only",
218 "result" => ["\\use_non_tex_fonts $useNonTexFont"]);
219 push(@rElems, $elemntf);
220 if (defined($inputEncoding)) {
221 my $inputenc = newMatch("search" => '^\\\\inputencoding\s+(' . $inputEncoding->{search} . ')',
222 "filetype" => "replace_only",
223 "result" => ["\\inputencoding " . $inputEncoding->{out}]);
224 push(@rElems, $inputenc);
226 setMatching(\@rElems);
232 sub checkForPreamble($)
236 if ($l =~ /^\\begin_preamble\s*$/) {
238 $selem{type} = "preamble";
240 unshift(@stack, \%selem);
241 my $rElem = newMatch("ext" => [".eps", ".png"],
242 "search" => '^\\\\(photo|ecvpicture)(.*\{)(.*)\}',
244 "result" => ["\\", "1", "2", "3", "}"]);
245 setMatching([$rElem]);
251 sub checkForLayoutStart($)
255 if ($l =~ /^\\begin_layout\s+(.*)$/) {
256 #print "started layout\n";
258 $selem{type} = "layout";
260 unshift(@stack, \%selem);
261 if ($selem{name} =~ /^(Picture|Photo)$/ ) {
262 my $rElem = newMatch("ext" => [".eps", ".png"],
264 "result" => ["", "", ""]);
265 setMatching([$rElem]);
272 sub checkForInsetStart($)
276 if ($l =~ /^\\begin_inset\s+(.*)$/) {
277 #print "started inset\n";
279 $selem{type} = "inset";
281 unshift(@stack, \%selem);
282 if ($selem{name} =~ /^(Graphics|External)$/) {
283 my $rElem = newMatch("search" => '^\s+filename\s+(.+)$',
284 "filetype" => "copy_only",
285 "result" => ["\tfilename ", "", ""]);
286 setMatching([$rElem]);
293 sub checkForLatexCommand($)
297 if ($stack[0]->{type} eq "inset") {
298 if ($l =~ /^LatexCommand\s+([^\s]+)\s*$/) {
300 if ($stack[0]->{name} =~ /^CommandInset\s+bibtex$/) {
301 if ($param eq "bibtex") {
302 my $rElem1 = newMatch("ext" => ".bib",
303 "filetype" => "prefix_for_list",
304 "search" => '^bibfiles\s+\"(.+)\"',
305 "result" => ["bibfiles \"", "1", "\""]);
306 my $rElem2 = newMatch("ext" => ".bst",
307 "filetype" => "prefix_for_list",
308 "search" => '^options\s+\"(.+)\"',
309 "result" => ["options \"", "1", "\""]);
310 setMatching([$rElem1, $rElem2]);
313 elsif ($stack[0]->{name} =~ /^CommandInset\s+include$/) {
314 if ($param =~ /^(verbatiminput\*?|lstinputlisting)$/) {
315 my $rElem = newMatch("search" => '^filename\s+\"(.+)\"',
316 "filetype" => "copy_only",
317 "result" => ["filename \"", "", "\""]);
318 setMatching([$rElem]);
320 elsif ($param =~ /^(include|input)$/) {
321 my $rElem = newMatch("search" => '^filename\s+\"(.+)\"',
322 "filetype" => "interpret",
323 "result" => ["filename \"", "", "\""]);
324 setMatching([$rElem]);
333 # parse the given line
334 # returns a hash with folloving values
335 # found: 1 if line matched some regex
336 # fileidx: index into result
337 # ext: list of possible extensions to use for a valid file
338 # filelist: list of found file-pathes (may be more then one, e.g. in bibfiles spec)
339 # separator: to be used while concatenating the filenames
340 # filetype: prefix_only,replace_only,copy_only,interpret
341 # same as before, but without 'prefix_for_list'
346 return({"found" => 0}) if (checkForHeader($l));
347 return({"found" => 0}) if (checkForPreamble($l));
348 return({"found" => 0}) if (checkForEndBlock($l));
349 return({"found" => 0}) if (checkForLayoutStart($l));
350 return({"found" => 0}) if (checkForInsetStart($l));
351 return({"found" => 0}) if (checkForLatexCommand($l));
352 if (defined($stack[0])) {
353 my $rMatch = getMatching();
354 for my $m ( @{$rMatch}) {
355 my $search = getSearch($m);
356 if ($l =~ /$search/) {
357 my @matches = ($1, $2, $3, $4);
358 my $filetype = getFileType($m);
359 my @result2 = @{getResult($m)};
361 for my $r (@result2) {
366 if ($filetype eq "replace_only") {
368 my %result = ("found" => 1,
369 "filetype" => $filetype,
370 "result" => \@result2);
374 my $fileidx = getFileIdx($m);
375 my $filename = $matches[$fileidx-1];
376 if ($filename !~ /^\.*$/) {
377 my %result = ("found" => 1,
378 "fileidx" => $fileidx,
380 "result" => \@result2);
381 if ($filetype eq "prefix_for_list") {
382 # bibfiles|options in CommandInset bibtex
383 my @filenames = split(',', $filename);
384 $result{"separator"} = ",";
385 $result{"filelist"} = \@filenames;
386 $result{"filetype"} = "prefix_only";
389 $result{"separator"} = "";
390 $result{"filelist"} = [$filename];
391 $result{"filetype"} = $filetype;
399 return({"found" => 0});