Restructure repository: organize tools by purpose, create what search tool
- Move single-file tools to tools/ organized by category (security, forensics, data, etc.) - Move multi-file projects to projects/ (go-tools, puzzlebox, timesketch, rust-tools) - Move system scripts to scripts/ (proxy, display, setup, windows) - Organize config files in config/ (shell, visidata, applications) - Move experimental tools to archive/experimental - Create 'what' fuzzy search tool with progressive enhancement (ollama->fzf->grep) - Add initial metadata database for intelligent tool discovery - Preserve git history using 'git mv' commands
This commit is contained in:
140
projects/go-tools/go/gobetween/gobetween.go
Normal file
140
projects/go-tools/go/gobetween/gobetween.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func printUsage() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s [options] <range specification> [file]\n", os.Args[0])
|
||||
fmt.Fprintln(os.Stderr, "Options:")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintln(os.Stderr, "\nRange specification examples:")
|
||||
fmt.Fprintln(os.Stderr, "10,20 Reads lines 10 to 20 from the input")
|
||||
fmt.Fprintln(os.Stderr, "15:+5 Reads 5 lines starting from line 15")
|
||||
fmt.Fprintln(os.Stderr, "3 Reads from line 3 to the end of the file")
|
||||
fmt.Fprintln(os.Stderr, "+2 Reads the first 2 lines")
|
||||
fmt.Fprintln(os.Stderr, "Please ensure you input valid range specifications and file paths.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func parseArgs(args []string) (int, int, string, error) {
|
||||
var filename string
|
||||
var start, length, end int
|
||||
found := false
|
||||
|
||||
// Concatenate all arguments to a single string for easier parsing
|
||||
joinedArgs := strings.Join(args, " ")
|
||||
|
||||
// Regular expression to match ranges and numbers
|
||||
rangeRegex := regexp.MustCompile(`((\d+)?([ :,;-]))(\+)?(\d+)`)
|
||||
range2Regex := regexp.MustCompile(`((\d+)([ :,;-]))`)
|
||||
range3Regex := regexp.MustCompile(`(\+)?(\d+)`)
|
||||
|
||||
matches := rangeRegex.FindStringSubmatch(joinedArgs)
|
||||
|
||||
if matches != nil {
|
||||
//check if start was defined
|
||||
if matches[2] != "" {
|
||||
start, _ = strconv.Atoi(matches[2]) // Convert start line to integer
|
||||
} else {
|
||||
start = 1
|
||||
}
|
||||
if matches[4] == "+" { // Check if it's a relative length
|
||||
length, _ = strconv.Atoi(matches[5]) // Convert length to integer
|
||||
end = start + length - 1
|
||||
} else {
|
||||
end, _ = strconv.Atoi(matches[5]) // Convert end line to integer
|
||||
}
|
||||
// Remove the matched part from the arguments
|
||||
joinedArgs = strings.Replace(joinedArgs, matches[0], "", 1)
|
||||
found = true
|
||||
} else {
|
||||
matches = range2Regex.FindStringSubmatch(joinedArgs)
|
||||
if matches != nil {
|
||||
start, _ = strconv.Atoi(matches[2]) // Convert start line to integer
|
||||
end = -1
|
||||
// Remove the matched part from the arguments
|
||||
joinedArgs = strings.Replace(joinedArgs, matches[0], "", 1)
|
||||
found = true
|
||||
} else {
|
||||
matches = range3Regex.FindStringSubmatch(joinedArgs)
|
||||
if matches != nil {
|
||||
if matches[1] == "+" { // Check if it's a relative length
|
||||
length, _ := strconv.Atoi(matches[2]) // Convert length to integer
|
||||
start = 1
|
||||
end = start + length - 1
|
||||
} else { // Otherwise convert it to an absolute length
|
||||
start, _ = strconv.Atoi(matches[2]) // Convert start line to integer
|
||||
end = -1
|
||||
// Remove the matched part from the arguments
|
||||
}
|
||||
joinedArgs = strings.Replace(joinedArgs, matches[0], "", 1)
|
||||
found = true
|
||||
} else {
|
||||
found = false
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up and identify the filename, if present
|
||||
joinedArgs = strings.TrimSpace(joinedArgs)
|
||||
if joinedArgs != "" && !found {
|
||||
// If we didn't find numbers, interpret the remaining as filename
|
||||
filename = joinedArgs
|
||||
} else if joinedArgs != "" {
|
||||
// Otherwise, interpret any non-empty remaining part as filename
|
||||
filename = joinedArgs
|
||||
}
|
||||
|
||||
if !found {
|
||||
return 0, 0, "", fmt.Errorf("no valid range or line number found")
|
||||
}
|
||||
|
||||
return start, end, filename, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
printUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
startIndex, endIndex, filename, err := parseArgs(args)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing arguments: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Detemine the input source (file or stdin)
|
||||
inputSource := os.Stdin
|
||||
if filename != "" {
|
||||
inputSource, err = os.Open(filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open file: %v\n", err)
|
||||
}
|
||||
defer inputSource.Close()
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(inputSource)
|
||||
//print all lines from line buner start to linenumber end unless linenumber end is -1
|
||||
for i := 1; scanner.Scan(); i++ {
|
||||
if startIndex <= i && (i <= endIndex || endIndex == -1) {
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user