cmd/cpe2cve/fieldstoskip.go (108 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "fmt" "sort" "strconv" "strings" ) // filedsToSkip is a custom type to be recognized by flag.Parse(). // It maps comma-separated numbers from command line option to a set of integers. // It also provides methods for dropping configured indices from a slice. type fieldsToSkip map[int]bool // skipFields removes elements from fields slice as per config func (fs fieldsToSkip) skipFields(fields []string) []string { j := 0 for i := 0; i < len(fields); i++ { if fs[i] { continue } fields[j] = fields[i] j++ } return fields[:j] } // appendAt appends and element to a slice at position at after skipping configured fields. // Negative pos skips the next element. func (fs fieldsToSkip) appendAt(to []string, args ...interface{}) []string { to = fs.skipFields(to) fields := map[int]string{} keys := make([]int, 0, len(args)/2) pos := -1 for _, arg := range args { switch arg := arg.(type) { case int: pos = arg if pos >= 0 { keys = append(keys, pos) } case string: if pos < 0 { break } fields[pos] = arg pos = -1 default: panic(fmt.Sprintf("appendAt: unsupported type %T", arg)) } } sort.Ints(keys) for _, at := range keys { if at > len(to) { at = len(to) } out := make([]string, 0, len(to)+1) out = append(out, to[:at]...) out = append(out, fields[at]) out = append(out, to[at:]...) to = out } return to } // part of flag.Value interface implementation func (fs fieldsToSkip) String() string { keys := make([]int, 0, len(fs)) for k := range fs { keys = append(keys, k) } sort.Ints(keys) fss := make([]string, len(keys)) for i, v := range keys { fss[i] = fmt.Sprintf("%d", v+1) } return strings.Join(fss, ",") } // part of flag.Value interface implementation func (fs *fieldsToSkip) Set(val string) error { if *fs == nil { *fs = fieldsToSkip{} } for _, v := range strings.Split(val, ",") { nn, err := atoii(v) if err != nil { return fmt.Errorf("bad fieldsToSkip value: %q: %v", v, err) } for _, n := range nn { if n < 1 { return fmt.Errorf("illegal field index %d", n) } (*fs)[n-1] = true } } return nil } // atoii parses ranges of positive integers from string r. // E.g., it will return [1, 2, 3, 4] for "1-4", [3] for "3"; // Open ranges (e.g. "-3", "3-") are not allowed and are parsed as a single integer. // Any character other than digit or '-' in the input will trigger an error. func atoii(r string) ([]int, error) { var ret []int fromto := strings.Split(r, "-") if len(fromto) != 1 && len(fromto) != 2 { return nil, fmt.Errorf("illegal range: %q", r) } start, err := strconv.Atoi(fromto[0]) if err != nil { return nil, err } ret = append(ret, start) if len(fromto) == 1 { return ret, nil } end, err := strconv.Atoi(fromto[1]) if err != nil { return nil, err } for i := start + 1; i < end; i++ { ret = append(ret, i) } ret = append(ret, end) return ret, nil }