From 2686154c6f4d260c3b27b08d3efcf7c59d7488e5 Mon Sep 17 00:00:00 2001 From: Aaron Johnon Date: Wed, 28 Aug 2024 23:27:56 -0500 Subject: [PATCH] Added grouping functionality --- nsencoder.go | 108 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 13 deletions(-) diff --git a/nsencoder.go b/nsencoder.go index fb363de..2cdfdfd 100644 --- a/nsencoder.go +++ b/nsencoder.go @@ -11,12 +11,21 @@ import ( ) func main() { - // Define the shift, hex, and space flags + // Define the shift, hex, space, and grouping flags shift := flag.Int("s", 0, "Shift value for alphabet positions (can be negative)") useHex := flag.Bool("x", false, "Encode numbers in hexadecimal") encodeSpaces := flag.Bool("S", false, "Encode spaces as '00'") + groupSize := flag.Int("g", 2, "Group size for output digits (minimum value of 2, default 2)") flag.Parse() + // Check for invalid group size + if *groupSize == 1 { + fmt.Fprintln(os.Stderr, "Error: Minimum group size is 2. Exiting.") + os.Exit(1) + } else if *groupSize <= 0 { + *groupSize = 2 + } + // Check if input is being piped or passed as an argument stat, _ := os.Stdin.Stat() if (stat.Mode() & os.ModeCharDevice) != 0 { @@ -42,7 +51,7 @@ func main() { if unicode.IsLetter(char) { // If there was a number being processed, add it to the result first if currentNumber != "" { - appendNumber(&result, currentNumber, *useHex) + appendNumber(&result, currentNumber, *useHex, *groupSize) currentNumber = "" } // Get the position of the character in the alphabet (A = 1, B = 2, ..., Z = 26) @@ -62,14 +71,14 @@ func main() { } else if char == ' ' && *encodeSpaces { // Encode space as '00' if the -S flag is set if currentNumber != "" { - appendNumber(&result, currentNumber, *useHex) + appendNumber(&result, currentNumber, *useHex, *groupSize) currentNumber = "" } result = append(result, "00") } else { // If there was a number being processed and now a non-digit/non-letter appears, append it if currentNumber != "" { - appendNumber(&result, currentNumber, *useHex) + appendNumber(&result, currentNumber, *useHex, *groupSize) currentNumber = "" } } @@ -77,22 +86,95 @@ func main() { // If there's any remaining number at the end of the input, append it if currentNumber != "" { - appendNumber(&result, currentNumber, *useHex) + appendNumber(&result, currentNumber, *useHex, *groupSize) } - // Join the result slice into a space-separated string and print it - fmt.Println(strings.Join(result, " ")) + // Format output with proper grouping + finalOutput := groupOutput(result, *groupSize) + fmt.Println(finalOutput) } // appendNumber appends a formatted number to the result slice -func appendNumber(result *[]string, number string, useHex bool) { - if useHex { - num, err := strconv.Atoi(number) - if err == nil { - *result = append(*result, fmt.Sprintf("0x%X", num)) +func appendNumber(result *[]string, number string, useHex bool, groupSize int) { + var formatted string + num, err := strconv.Atoi(number) + if err != nil { + return + } + + // Set maximum values based on group size and mode + var maxValue int + if groupSize == 2 || groupSize == 4 { + if useHex { + maxValue = 255 // 0xFF + } else { + maxValue = 99 // 0d99 } } else { - *result = append(*result, "0d"+number) + maxDigits := groupSize - 2 // for "0x" or "0d" prefix + maxValue = intMaxValue(useHex, maxDigits) } + + if num > maxValue { + fmt.Fprintf(os.Stderr, "Warning: Number %d is too large for group size %d. Using maximum value %d.\n", num, groupSize, maxValue) + num = maxValue + } + + if useHex { + formatted = fmt.Sprintf("0x%X", num) + } else { + formatted = fmt.Sprintf("0d%d", num) + } + + *result = append(*result, formatted) +} + +// intMaxValue calculates the maximum value that fits within the specified group size +func intMaxValue(useHex bool, maxDigits int) int { + if useHex { + return (1 << uint(maxDigits*4)) - 1 // Maximum hexadecimal value fitting in maxDigits + } + return intPow(10, maxDigits) - 1 // Maximum decimal value fitting in maxDigits +} + +// intPow calculates integer power +func intPow(base, exp int) int { + result := 1 + for exp > 0 { + result *= base + exp-- + } + return result +} + +// groupOutput groups the output into specified sizes, ensuring numbers are separate +func groupOutput(result []string, groupSize int) string { + var output []string + var currentGroup string + + for _, item := range result { + if strings.HasPrefix(item, "0x") || strings.HasPrefix(item, "0d") { + // If the current group is not empty, add it to the output + if currentGroup != "" { + output = append(output, currentGroup) + currentGroup = "" + } + // Numbers are placed in their own group + output = append(output, item) + } else { + currentGroup += item + if len(currentGroup) >= groupSize { + output = append(output, currentGroup[:groupSize]) + currentGroup = currentGroup[groupSize:] + } + } + } + + // Append any remaining characters in the current group + if currentGroup != "" { + output = append(output, currentGroup) + } + + return strings.Join(output, " ") }