Add comment conversion tool.
This is a utility to switch comments from /* C-style */ to // C++-style.
It's purely aesthetic, but it matches how most of Google C++ looks.
Running it over libssl, the script seems to get all but one or two cases
right.
We may also wish to convert the C code for consistency while we're here.
We've accidentally put both styles of comments all over the place, so
our toolchains can tolerate // in C.
Bug: 132
Change-Id: If2f4d58c0a4ad8f9a2113705435bff90e0dabcc3
Reviewed-on: https://boringssl-review.googlesource.com/18064
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/util/convert_comments.go b/util/convert_comments.go
new file mode 100644
index 0000000..f5171c3
--- /dev/null
+++ b/util/convert_comments.go
@@ -0,0 +1,216 @@
+// Copyright (c) 2017, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+package main
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+// convert_comments.go converts C-style block comments to C++-style line
+// comments. A block comment is converted if all of the following are true:
+//
+// * The comment begins after the first blank line, to leave the license
+// blocks alone.
+//
+// * There are no characters between the '*/' and the end of the line.
+//
+// * Either one of the following are true:
+//
+// - The comment fits on one line.
+//
+// - Each line the comment spans begins with N spaces, followed by '/*' for
+// the initial line or ' *' for subsequent lines, where N is the same for
+// each line.
+//
+// This tool is a heuristic. While it gets almost all cases correct, the final
+// output should still be looked over and fixed up as needed.
+
+// allSpaces returns true if |s| consists entirely of spaces.
+func allSpaces(s string) bool {
+ return strings.IndexFunc(s, func(r rune) bool { return r != ' ' }) == -1
+}
+
+// isContinuation returns true if |s| is a continuation line for a multi-line
+// comment indented to the specified column.
+func isContinuation(s string, column int) bool {
+ if len(s) < column+2 {
+ return false
+ }
+ if !allSpaces(s[:column]) {
+ return false
+ }
+ return s[column:column+2] == " *"
+}
+
+// indexFrom behaves like strings.Index but only reports matches starting at
+// |idx|.
+func indexFrom(s, sep string, idx int) int {
+ ret := strings.Index(s[idx:], sep)
+ if ret < 0 {
+ return -1
+ }
+ return idx + ret
+}
+
+// writeLine writes |line| to |out|, followed by a newline.
+func writeLine(out *bytes.Buffer, line string) {
+ out.WriteString(line)
+ out.WriteByte('\n')
+}
+
+func convertComments(in []byte) []byte {
+ lines := strings.Split(string(in), "\n")
+ var out bytes.Buffer
+
+ // Account for the trailing newline.
+ if len(lines) > 0 && len(lines[len(lines)-1]) == 0 {
+ lines = lines[:len(lines)-1]
+ }
+
+ // Find the license block separator.
+ for len(lines) > 0 {
+ line := lines[0]
+ lines = lines[1:]
+ writeLine(&out, line)
+ if len(line) == 0 {
+ break
+ }
+ }
+
+ // inComment is true if we are in the middle of a comment.
+ var inComment bool
+ // comment is the currently buffered multi-line comment to convert. If
+ // |inComment| is true and it is nil, the current multi-line comment is
+ // not convertable and we copy lines to |out| as-is.
+ var comment []string
+ // column is the column offset of |comment|.
+ var column int
+ for len(lines) > 0 {
+ line := lines[0]
+ lines = lines[1:]
+
+ var idx int
+ if inComment {
+ // Stop buffering if this comment isn't eligible.
+ if comment != nil && !isContinuation(line, column) {
+ for _, l := range comment {
+ writeLine(&out, l)
+ }
+ comment = nil
+ }
+
+ // Look for the end of the current comment.
+ idx = strings.Index(line, "*/")
+ if idx < 0 {
+ if comment != nil {
+ comment = append(comment, line)
+ } else {
+ writeLine(&out, line)
+ }
+ continue
+ }
+
+ inComment = false
+ if comment != nil {
+ if idx == len(line)-2 {
+ // This is a convertable multi-line comment.
+ if idx >= column+2 {
+ // |idx| may be equal to
+ // |column| + 1, if the line is
+ // a '*/' on its own. In that
+ // case, we discard the line.
+ comment = append(comment, line[:idx])
+ }
+ for _, l := range comment {
+ out.WriteString(l[:column])
+ out.WriteString("//")
+ writeLine(&out, strings.TrimRight(l[column+2:], " "))
+ }
+ comment = nil
+ continue
+ }
+
+ // Flush the buffered comment unmodified.
+ for _, l := range comment {
+ writeLine(&out, l)
+ }
+ comment = nil
+ }
+ idx += 2
+ }
+
+ // Parse starting from |idx|, looking for either a convertable
+ // line comment or a multi-line comment.
+ for {
+ idx = indexFrom(line, "/*", idx)
+ if idx < 0 {
+ writeLine(&out, line)
+ break
+ }
+
+ endIdx := indexFrom(line, "*/", idx)
+ if endIdx < 0 {
+ inComment = true
+ if allSpaces(line[:idx]) {
+ // The comment is, so far, eligible for conversion.
+ column = idx
+ comment = []string{line}
+ }
+ break
+ }
+
+ if endIdx != len(line)-2 {
+ // Continue parsing for more comments in this line.
+ idx = endIdx + 2
+ continue
+ }
+
+ out.WriteString(line[:idx])
+
+ // Google C++ style prefers two spaces before a
+ // comment if it is on the same line as code,
+ // but clang-format has been placing one space
+ // for block comments. Fix this.
+ if !allSpaces(line[:idx]) {
+ if line[idx-1] != ' ' {
+ out.WriteString(" ")
+ } else if line[idx-2] != ' ' {
+ out.WriteString(" ")
+ }
+ }
+
+ out.WriteString("//")
+ writeLine(&out, strings.TrimRight(line[idx+2:endIdx], " "))
+ break
+ }
+ }
+
+ return out.Bytes()
+}
+
+func main() {
+ for _, arg := range os.Args[1:] {
+ in, err := ioutil.ReadFile(arg)
+ if err != nil {
+ panic(err)
+ }
+ if err := ioutil.WriteFile(arg, convertComments(in), 0666); err != nil {
+ panic(err)
+ }
+ }
+}