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+"default"\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", "}"]);
246 # Remove comments from preamble
247 my $comments = newMatch("search" => '^([^%]*)([%]+)([^%]*)$',
248 "filetype" => "replace_only",
249 "result" => ["1", "2"]);
250 setMatching([$rElem, $comments]);
256 sub checkForLayoutStart($)
260 if ($l =~ /^\\begin_layout\s+(.*)$/) {
261 #print "started layout\n";
263 $selem{type} = "layout";
265 unshift(@stack, \%selem);
266 if ($selem{name} =~ /^(Picture|Photo)$/ ) {
267 my $rElem = newMatch("ext" => [".eps", ".png"],
269 "result" => ["", "", ""]);
270 setMatching([$rElem]);
277 sub checkForInsetStart($)
281 if ($l =~ /^\\begin_inset\s+(.*)$/) {
282 #print "started inset\n";
284 $selem{type} = "inset";
286 unshift(@stack, \%selem);
287 if ($selem{name} =~ /^(Graphics|External)$/) {
288 my $rElem = newMatch("search" => '^\s+filename\s+(.+)$',
289 "filetype" => "copy_only",
290 "result" => ["\tfilename ", "", ""]);
291 setMatching([$rElem]);
298 sub checkForLatexCommand($)
302 if ($stack[0]->{type} eq "inset") {
303 if ($l =~ /^LatexCommand\s+([^\s]+)\s*$/) {
305 if ($stack[0]->{name} =~ /^CommandInset\s+bibtex$/) {
306 if ($param eq "bibtex") {
307 my $rElem1 = newMatch("ext" => ".bib",
308 "filetype" => "prefix_for_list",
309 "search" => '^bibfiles\s+\"(.+)\"',
310 "result" => ["bibfiles \"", "1", "\""]);
311 my $rElem2 = newMatch("ext" => ".bst",
312 "filetype" => "prefix_for_list",
313 "search" => '^options\s+\"(.+)\"',
314 "result" => ["options \"", "1", "\""]);
315 setMatching([$rElem1, $rElem2]);
318 elsif ($stack[0]->{name} =~ /^CommandInset\s+include$/) {
319 if ($param =~ /^(verbatiminput\*?|lstinputlisting|inputminted)$/) {
320 my $rElem = newMatch("search" => '^filename\s+\"(.+)\"',
321 "filetype" => "copy_only",
322 "result" => ["filename \"", "", "\""]);
323 setMatching([$rElem]);
325 elsif ($param =~ /^(include|input)$/) {
326 my $rElem = newMatch("search" => '^filename\s+\"(.+)\"',
327 "filetype" => "interpret",
328 "result" => ["filename \"", "", "\""]);
329 setMatching([$rElem]);
338 # parse the given line
339 # returns a hash with folloving values
340 # found: 1 if line matched some regex
341 # fileidx: index into result
342 # ext: list of possible extensions to use for a valid file
343 # filelist: list of found file-pathes (may be more then one, e.g. in bibfiles spec)
344 # separator: to be used while concatenating the filenames
345 # filetype: prefix_only,replace_only,copy_only,interpret
346 # same as before, but without 'prefix_for_list'
351 return({"found" => 0}) if (checkForHeader($l));
352 return({"found" => 0}) if (checkForPreamble($l));
353 return({"found" => 0}) if (checkForEndBlock($l));
354 return({"found" => 0}) if (checkForLayoutStart($l));
355 return({"found" => 0}) if (checkForInsetStart($l));
356 return({"found" => 0}) if (checkForLatexCommand($l));
357 if (defined($stack[0])) {
358 my $rMatch = getMatching();
359 for my $m ( @{$rMatch}) {
360 my $search = getSearch($m);
361 if ($l =~ /$search/) {
362 my @matches = ($1, $2, $3, $4);
363 my $filetype = getFileType($m);
364 my @result2 = @{getResult($m)};
366 for my $r (@result2) {
371 if ($filetype eq "replace_only") {
373 my %result = ("found" => 1,
374 "filetype" => $filetype,
375 "result" => \@result2);
379 my $fileidx = getFileIdx($m);
380 my $filename = $matches[$fileidx-1];
381 if ($filename !~ /^\.*$/) {
382 my %result = ("found" => 1,
383 "fileidx" => $fileidx,
385 "result" => \@result2);
386 if ($filetype eq "prefix_for_list") {
387 # bibfiles|options in CommandInset bibtex
388 my @filenames = split(',', $filename);
389 $result{"separator"} = ",";
390 $result{"filelist"} = \@filenames;
391 $result{"filetype"} = "prefix_only";
394 $result{"separator"} = "";
395 $result{"filelist"} = [$filename];
396 $result{"filetype"} = $filetype;
404 return({"found" => 0});