Expand Indented File List to Full Paths
This function walks through a file that has paths indicated by indentation level, as shown in the following example:
lang
perl
src
math.pl
input.pl
readme
lib
tools.pm
c
inc
profile.h
names.h
src
update.c
readme
The program is passed a match string as an argument. It scans the result of the diamond operator (<>) input (either STDIN, or filenames passed as the arguments following the match string), and for every match, it prints out the full path of the matched line. For example, if it were asked to find "readme" with the previous example as input, it would print out the following:
lang/perl/src/readme
lang/c/readme
The program tracks the text printed at each unique indent level up to the indent of the current line; if the current line is less indented than previous lines, any previous indents of an equal or greater number of spaces are no longer tracked. It uses the Perl feature that you can truncate an array by assigning to $#array, which is the variable that holds the index of the last element of the array.
Source Code
1. # arguments: matchstring [filename1 [filename2 ...]]
2.
3. $match = shift @ARGV;
4.
5. while (<>) {
6.
7. # remove \n from input
8. chomp;
9.
10. # process all lines except completely blank ones
11. unless (/^\s*$/) {
12.
13. # how many initial spaces in the line?
14. /( *)/;
15. $spaces = $1;
16.
17. # chop the array at that point
18. $#indentlabels = $spaces;
19.
20. # save line text after spaces
21. $indentlabels[$spaces] = $';
22.
23. # does the line match the match string
24. if (/$match/) {
25.
26. # display path
27. foreach $l (@indentlabels) {
28. print $l if defined($l);
29. }
30. print "\n";
31. }
32.
33. # add the separator for future printing
34. $indentlabels[$spaces] .= "/";
35. }
36. }
Suggestions
Check the regular expressions on lines 11 and 14 to ensure that they are correct. What number of spaces at the beginning of a line is most likely to cause problems? Probably zero. Walk through the code with a line that has no spaces at the beginning. How long will a particular entry remain in the @indentlabels array?
Hints
Walk through the code with the following match strings and input files:
Match twice at different indents: match eq "abc", file contains:
abc
abc
Match once at indent after outdent: match eq "abc", file contains:
test
directory
xyz
abc
Match is substring of actual value: match eq "abc", file contains:
ab
cd
abcd
Explanation of the Bug
Line 15 has a B.expression error:
$spaces = $1;
At line 15, the $1 string contains the piece of the string that matched the part of the regular expression on line 14 that was in parentheses. In this case, the regular expression is ( *), so $1 contains a certain number of space characters. However, it is used in the program as if it contained the number of spaces as an integer. The actual spaces always evaluates to 0 when converted to an integer. Therefore, the program will treat every line as if it were indented 0 spaces, which means it will keep chopping @indentlabels back to one element and never display full paths as it is supposed to.
Line 15 needs to be changed to read as follows:
$spaces = length($1);
|