📄 cvs2cl.pl
字号:
if (defined ($$qunkref{'tags'})) { foreach my $tag (@{$$qunkref{'tags'}}) { $non_unanimous_tags{$tag} = 1; } } } # Any tag held by all qunks will be printed specially... but only if # there are multiple qunks in the first place! if ((scalar (@qunkrefs)) > 1) { foreach my $tag (keys (%non_unanimous_tags)) { my $everyone_has_this_tag = 1; foreach my $qunkref (@qunkrefs) { if ((! (defined ($$qunkref{'tags'}))) or (! (grep ($_ eq $tag, @{$$qunkref{'tags'}})))) { $everyone_has_this_tag = 0; } } if ($everyone_has_this_tag) { $unanimous_tags{$tag} = 1; delete $non_unanimous_tags{$tag}; } } } if ($XML_Output) { # If outputting XML, then our task is pretty simple, because we # don't have to detect common dir, common tags, branch prefixing, # etc. We just output exactly what we have, and don't worry about # redundancy or readability. foreach my $qunkref (@qunkrefs) { my $filename = $$qunkref{'filename'}; my $revision = $$qunkref{'revision'}; my $tags = $$qunkref{'tags'}; my $branch = $$qunkref{'branch'}; my $branchroots = $$qunkref{'branchroots'}; $filename = &xml_escape ($filename); # probably paranoia $revision = &xml_escape ($revision); # definitely paranoia $beauty .= "<file>\n"; $beauty .= "<name>${filename}</name>\n"; $beauty .= "<revision>${revision}</revision>\n"; if ($branch) { $branch = &xml_escape ($branch); # more paranoia $beauty .= "<branch>${branch}</branch>\n"; } foreach my $tag (@$tags) { $tag = &xml_escape ($tag); # by now you're used to the paranoia $beauty .= "<tag>${tag}</tag>\n"; } foreach my $root (@$branchroots) { $root = &xml_escape ($root); # which is good, because it will continue $beauty .= "<branchroot>${root}</branchroot>\n"; } $beauty .= "</file>\n"; } # Theoretically, we could go home now. But as long as we're here, # let's print out the common_dir and utags, as a convenience to # the receiver (after all, earlier code calculated that stuff # anyway, so we might as well take advantage of it). if ((scalar (keys (%unanimous_tags))) > 1) { foreach my $utag ((keys (%unanimous_tags))) { $utag = &xml_escape ($utag); # the usual paranoia $beauty .= "<utag>${utag}</utag>\n"; } } if ($common_dir) { $common_dir = &xml_escape ($common_dir); $beauty .= "<commondir>${common_dir}</commondir>\n"; } # That's enough for XML, time to go home: return $beauty; } # Else not XML output, so complexly compactify for chordate # consumption. At this point we have enough global information # about all the qunks to organize them non-redundantly for output. if ($common_dir) { # Note that $common_dir still has its trailing slash $beauty .= "$common_dir: "; } if ($Show_Branches) { # For trailing revision numbers. my @brevisions; foreach my $branch (keys (%all_branches)) { foreach my $qunkref (@qunkrefs) { if ((defined ($$qunkref{'branch'})) and ($$qunkref{'branch'} eq $branch)) { if ($fbegun) { # kff todo: comma-delimited in XML too? Sure. $beauty .= ", "; } else { $fbegun = 1; } my $fname = substr ($$qunkref{'filename'}, length ($common_dir)); $beauty .= $fname; $$qunkref{'printed'} = 1; # Just setting a mark bit, basically if ($Show_Tags && (defined @{$$qunkref{'tags'}})) { my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}}); if (@tags) { $beauty .= " (tags: "; $beauty .= join (', ', @tags); $beauty .= ")"; } } if ($Show_Revisions) { # Collect the revision numbers' last components, but don't # print them -- they'll get printed with the branch name # later. $$qunkref{'revision'} =~ /.+\.([\d]+)$/; push (@brevisions, $1); # todo: we're still collecting branch roots, but we're not # showing them anywhere. If we do show them, it would be # nifty to just call them revision "0" on a the branch. # Yeah, that's the ticket. } } } $beauty .= " ($branch"; if (@brevisions) { if ((scalar (@brevisions)) > 1) { $beauty .= ".["; $beauty .= (join (',', @brevisions)); $beauty .= "]"; } else { $beauty .= ".$brevisions[0]"; } } $beauty .= ")"; } } # Okay; any qunks that were done according to branch are taken care # of, and marked as printed. Now print everyone else. foreach my $qunkref (@qunkrefs) { next if (defined ($$qunkref{'printed'})); # skip if already printed if ($fbegun) { $beauty .= ", "; } else { $fbegun = 1; } $beauty .= substr ($$qunkref{'filename'}, length ($common_dir)); # todo: Shlomo's change was this: # $beauty .= substr ($$qunkref{'filename'}, # (($common_dir eq "./") ? "" : length ($common_dir))); $$qunkref{'printed'} = 1; # Set a mark bit. if ($Show_Revisions || $Show_Tags) { my $started_addendum = 0; if ($Show_Revisions) { $started_addendum = 1; $beauty .= " ("; $beauty .= "$$qunkref{'revision'}"; } if ($Show_Tags && (defined $$qunkref{'tags'})) { my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}}); if ((scalar (@tags)) > 0) { if ($started_addendum) { $beauty .= ", "; } else { $beauty .= " (tags: "; } $beauty .= join (', ', @tags); $started_addendum = 1; } } if ($started_addendum) { $beauty .= ")"; } } } # Unanimous tags always come last. if ($Show_Tags && %unanimous_tags) { $beauty .= " (utags: "; $beauty .= join (', ', keys (%unanimous_tags)); $beauty .= ")"; } # todo: still have to take care of branch_roots? $beauty = "* $beauty:"; return $beauty;}sub common_path_prefix (){ my $path1 = shift; my $path2 = shift; my ($dir1, $dir2); (undef, $dir1, undef) = fileparse ($path1); (undef, $dir2, undef) = fileparse ($path2); # Transmogrify Windows filenames to look like Unix. # (It is far more likely that someone is running cvs2cl.pl under # Windows than that they would genuinely have backslashes in their # filenames.) $dir1 =~ tr#\\#/#; $dir2 =~ tr#\\#/#; my $accum1 = ""; my $accum2 = ""; my $last_common_prefix = ""; while ($accum1 eq $accum2) { $last_common_prefix = $accum1; last if ($accum1 eq $dir1); my ($tmp1) = split (/\//, (substr ($dir1, length ($accum1)))); my ($tmp2) = split (/\//, (substr ($dir2, length ($accum2)))); $accum1 .= "$tmp1/" if ((defined ($tmp1)) and $tmp1); $accum2 .= "$tmp2/" if ((defined ($tmp2)) and $tmp2); } return $last_common_prefix;}sub preprocess_msg_text (){ my $text = shift; # Strip out carriage returns (as they probably result from DOSsy editors). $text =~ s/\r\n/\n/g; # If it *looks* like two newlines, make it *be* two newlines: $text =~ s/\n\s*\n/\n\n/g; if ($XML_Output) { $text = &xml_escape ($text); $text = "<msg>${text}</msg>\n"; } elsif (! $No_Wrap) { # Strip off lone newlines, but only for lines that don't begin with # whitespace or a mail-quoting character, since we want to preserve # that kind of formatting. Also don't strip newlines that follow a # period; we handle those specially next. And don't strip # newlines that precede an open paren. 1 while ($text =~ s/(^|\n)([^>\s].*[^.\n])\n([^>\n])/$1$2 $3/g); # If a newline follows a period, make sure that when we bring up the # bottom sentence, it begins with two spaces. 1 while ($text =~ s/(^|\n)([^>\s].*)\n([^>\n])/$1$2 $3/g); } return $text;}sub last_line_len (){ my $files_list = shift; my @lines = split (/\n/, $files_list); my $last_line = pop (@lines); return length ($last_line);}# A custom wrap function, sensitive to some common constructs used in# log entries.sub wrap_log_entry (){ my $text = shift; # The text to wrap. my $left_pad_str = shift; # String to pad with on the left. # These do NOT take left_pad_str into account: my $length_remaining = shift; # Amount left on current line. my $max_line_length = shift; # Amount left for a blank line. my $wrapped_text = ""; # The accumulating wrapped entry. my $user_indent = ""; # Inherited user_indent from prev line. my $first_time = 1; # First iteration of the loop? my $suppress_line_start_match = 0; # Set to disable line start checks. my @lines = split (/\n/, $text); while (@lines) # Don't use `foreach' here, it won't work. { my $this_line = shift (@lines); chomp $this_line; if ($this_line =~ /^(\s+)/) { $user_indent = $1; } else { $user_indent = ""; } # If it matches any of the line-start regexps, print a newline now... if ($suppress_line_start_match) { $suppress_line_start_match = 0; } elsif (($this_line =~ /^(\s*)\*\s+[a-zA-Z0-9]/) || ($this_line =~ /^(\s*)\* [a-zA-Z0-9_\.\/\+-]+/) || ($this_line =~ /^(\s*)\([a-zA-Z0-9_\.\/\+-]+(\)|,\s*)/) || ($this_line =~ /^(\s+)(\S+)/) || ($this_line =~ /^(\s*)- +/) || ($this_line =~ /^()\s*$/) || ($this_line =~ /^(\s*)\*\) +/) || ($this_line =~ /^(\s*)[a-zA-Z0-9](\)|\.|\:) +/)) { # Make a line break immediately, unless header separator is set # and this line is the first line in the entry, in which case # we're getting the blank line for free already and shouldn't # add an extra one. unless (($After_Header ne " ") and ($first_time)) { if ($this_line =~ /^()\s*$/) { $suppress_line_start_match = 1; $wrapped_text .= "\n${left_pad_str}"; } $wrapped_text .= "\n${left_pad_str}"; } $length_remaining = $max_line_length - (length ($user_indent)); } # Now that any user_indent has been preserved, strip off leading # whitespace, so up-folding has no ugly side-effects. $this_line =~ s/^\s*//; # Accumulate the line, and adjust parameters for next line. my $this_len = length ($this_line); if ($this_len == 0) { # Blank lines should cancel any user_indent level. $user_indent = ""; $length_remaining = $max_line_length; } elsif ($this_len >= $length_remaining) # Line too long, try breaking it. { # Walk backwards from the end. At first acceptable spot, break # a new line. my $idx = $length_remaining - 1; if ($idx < 0) { $idx = 0 }; while ($idx > 0) { if (substr ($this_line, $idx, 1) =~ /\s/) { my $line_now = substr ($this_line, 0, $idx); my $next_line = substr ($this_line, $idx); $this_line = $line_now; # Clean whitespace off the end. chomp $this_line; # The current line is ready to be printed. $this_line .= "\n${left_pad_str}"; # Make sure the next line is allowed full room. $length_remaining = $max_line_length - (length ($user_indent)); # Strip next_line, but then preserve any user_indent. $next_line =~ s/^\s*//; # Sneak a peek at the user_indent of the upcoming line, so # $next_line (which will now precede it) can inherit that # indent level. Otherwise, use whatever user_indent level # we currently have, which might be none. my $next_next_line = shift (@lines); if ((defined ($next_next_line)) && ($next_next_line =~ /^(\s+)/)) { $next_line = $1 . $next_line if (defined ($1)); # $length_remaining = $max_line_length - (length ($1)); $next_next_line =~ s/^\s*//; } else { $next_line = $user_indent . $next_line; } if (defined ($next_next_line)) { unshift (@lines, $next_next_line); } unshift (@lines, $next_line); # Our new next line might, coincidentally, begin with one of # the line-start regexps, so we temporarily turn off # sensitivity to that until we're past the line. $suppress_line_start_match = 1; last; } else { $idx--; } } if ($idx == 0) { # We bottomed out because the line is longer than the # available space. But that could be because the space is # small, or because the line is longer than even the maximum # possible space. Handle both cases below. if ($length_remaining == ($max_line_length - (length ($user_indent)))) { # The line is simply too long -- there is no hope of ever # breaking it nicely, so just insert it verbatim, with # appropriate padding. $this_line = "\n${left_pad_str}${this_line}"; } else { # Can't break it here, but may be able to on the next round... unshift (@lines, $this_line); $length_remaining = $max_line_length - (length ($user_indent)); $this_line = "\n${left_pad_str}"; } } } else # $this_len < $length_remaining, so tack on what we can. { # Leave a note for the next iteration. $length_remaining = $length_remaining - $this_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -