/* * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. * * 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 nm import ( "bufio" "os" "strings" ) // MatchedItem represents a matched item type MatchedItem struct { ObjFile string Symbol string Type SymbolType } // MatchedFile represents a matched file type MatchedFile struct { ArFile string Items []*MatchedItem } // Query queries symbol in index files (allow wildcard). func Query(dir string, query string) (files []*MatchedFile, err error) { fis, err := os.ReadDir(dir) if err != nil { return } dir += "/" for _, fi := range fis { if fi.IsDir() { continue } idxFile := fi.Name() if !strings.HasSuffix(idxFile, ".pub") { continue } files = queryIndex(files, dir+fi.Name(), query) } return } func queryIndex(files []*MatchedFile, idxFile, query string) []*MatchedFile { f, err := os.Open(idxFile) if err != nil { return files } defer f.Close() r := bufio.NewReader(f) line, err := r.ReadString('\n') if err != nil || !strings.HasPrefix(line, "nm ") { return files } var items []*MatchedItem arFile := line[3 : len(line)-1] objFile := "" query, flags := parseQuery(query) for { line, err = r.ReadString('\n') if err != nil { break } if strings.HasPrefix(line, "file ") { objFile = line[5 : len(line)-1] continue } typ := line[0] sym := line[2 : len(line)-1] if !match(sym, query, flags) { continue } items = append(items, &MatchedItem{ ObjFile: objFile, Symbol: sym, Type: SymbolType(typ), }) } if len(items) > 0 { files = append(files, &MatchedFile{ArFile: arFile, Items: items}) } return files } const ( flagSuffix = 1 << iota flagPrefix ) func parseQuery(query string) (text string, flags int) { if strings.HasSuffix(query, "*") { query = query[:len(query)-1] flags = flagPrefix } if strings.HasPrefix(query, "*") { query = query[1:] flags |= flagSuffix } text = query return } func match(s, query string, flags int) bool { switch flags { case 0: return s == query case flagPrefix: return strings.HasPrefix(s, query) case flagSuffix: return strings.HasSuffix(s, query) default: return strings.Contains(s, query) } }