blob: 73bae896504028d0a3d60e2674c1325e012f348e [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package codifier
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
// orderedStrings provides list functions that maintain an unsorted, ordered
// slice of strings, allowing additions of non-present, non-blank strings. That
// is, the list will be an ordered set provided that the list these functions
// are applied to is already an ordered set. File reading and appending
// functions are provided.
type orderedStrings []string
// contains returns whether the list contains the item.
func (o orderedStrings) contains(item string) bool {
for _, l := range o {
if l == item {
return true
}
}
return false
}
// Add appends the item(s) to the list if they are neither blank nor already
// present. Returns true iff all of the items are added.
//
// TODO(gboone@): This function is exported currently so that files can be added
// to changedFiles list by external functions. But changes to internal data
// should be made through Proc operators. Add operators to wrap these functions,
// eg (p *Proc) AddChangedFile(f string), to ordered_list_ops.go for managing
// the changedFiles list. Then unexport this function.
func (o *orderedStrings) Add(items ...string) bool {
if len(items) == 0 {
return false
}
allAdded := true
for _, item := range items {
if item == "" || o.contains(item) {
allAdded = false
continue
}
*o = append(*o, item)
}
return allAdded
}
func orderedStringsLoad(r io.Reader) (orderedStrings, error) {
scanner := bufio.NewScanner(r)
var o orderedStrings
for scanner.Scan() {
line := scanner.Text()
if l := strings.Index(line, "#"); l != -1 {
line = line[:l]
}
if line = strings.Trim(line, "\t "); line != "" {
if !o.Add(line) {
return nil, fmt.Errorf("found duplicate entry %q", line)
}
}
}
return o, scanner.Err()
}
// orderedStringsFromFile reads the lines into a string slice, stripping comment lines
// starting with '#' and text after '#' on lines.
func orderedStringsFromFile(filename string) (orderedStrings, error) {
filePath, err := resolveGnPath("", filename)
if err != nil {
return nil, fmt.Errorf("can't resolve path for filename %q: %w", filename, err)
}
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()
return orderedStringsLoad(f)
}
// findMissing returns the first candidate that isn't present in the named file.
// Return the index and the picked value, a boolean indicating whether one was
// found, and any error.
func findMissing(candidates []string, fileName string) (int, string, bool, error) {
skiplist, err := orderedStringsFromFile(fileName)
if err != nil {
return 0, "", false, err
}
for i, candidate := range candidates {
if !skiplist.contains(candidate) {
return i, candidate, true, nil
}
}
return 0, "", false, nil
}
// GoString serializes the string. Use like `fmt.Printf("%#v", o)`.
func (o orderedStrings) GoString() string {
out := ""
for i, item := range o {
out += fmt.Sprintf(" %d: %q", i, item)
if len(o)-1 != i {
out += "\n"
}
}
return out
}