/* This script is part of radix_info. Copyright (C) 2023, 2025 Adrien Hopkins This program is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package main import ( "errors" "flag" "fmt" "strconv" ) const ProgramVersion = "1.0.0" // The arguments to this program type args struct { Radix uint Compact bool FullMap bool ExactMTCLarge bool TotativeDigits bool DigitMapOnly bool LogRegularComplexities bool // If true, exit the program immediately after parsing args. Exit bool } func parseArgs() (args, error) { var a args flag.BoolVar(&a.Compact, "c", false, "Compact the output display") flag.BoolVar(&a.DigitMapOnly, "d", false, "Show only the digit map; incompatible with -m and -t") flag.BoolVar(&a.FullMap, "f", false, fmt.Sprintf("Show full digit map (up to %d) for every radix", maxSmallRadix)) flag.BoolVar(&a.LogRegularComplexities, "l", false, "Show the base-2 logarithm of the regular complexities") flag.BoolVar(&a.ExactMTCLarge, "m", false, fmt.Sprintf("Calculate exact MTC for very large radices (up to %d instead of %d), which may take a while.", maxExtended, maxNormal)) flag.BoolVar(&a.TotativeDigits, "t", false, "Calculate the radix's totative digits instead of just how many there are; incompatible with -c.") help := flag.Bool("?", false, "Get information about program usage then exit") version := flag.Bool("V", false, "Print program version then exit") flag.Parse() if *help { printHelp() return args{Exit: true}, nil } else if *version { fmt.Println("Radix Info version", ProgramVersion) return args{Exit: true}, nil } else if a.Compact && a.TotativeDigits { return args{}, errors.New("You cannot use both -t and -c at the same time.") } else if a.DigitMapOnly && (a.TotativeDigits || a.ExactMTCLarge) { return args{}, errors.New("You cannot use both -d and -t or -m at the same time.") } else if flag.NArg() < 1 { return args{}, errors.New("Please provide an argument (radix to study).") } else if flag.NArg() > 1 { return args{}, errors.New("Too many arguments provided.") } radix, err := strconv.ParseUint(flag.Arg(0), 0, 0) if err != nil { return args{}, uintParsingError(flag.Arg(0), err) } else if radix < 2 { return args{}, errors.New("Cannot use 0 or 1 as radices.") } else if radix > maxSmallRadix && a.DigitMapOnly && !a.FullMap { return args{}, errors.New("Used -d option, but digit map cannot be shown.") } a.Radix = uint(radix) return a, nil } // uintParsingError determines what error to show the user if radix parsing fails. // parsed is the radix string that was parsed and uintErr is the resulting error. func uintParsingError(parsed string, uintErr error) error { _, floatErr := strconv.ParseFloat(parsed, 64) if floatErr != nil { return fmt.Errorf("Error parsing radix: %w", uintErr) } var parsingErr *strconv.NumError if !errors.As(uintErr, &parsingErr) { return fmt.Errorf("Error parsing radix: %w", uintErr) } else if errors.Is(parsingErr.Err, strconv.ErrRange) { return fmt.Errorf("Radix is too large. Please use something smaller.") } else { return fmt.Errorf("Radix must be an unsigned integer.") } } func printHelp() { fmt.Println("Get important information about a radix.") fmt.Println("You must provide one argument, which is the radix to get information about.") fmt.Println("The radix must be an unsigned integer above 1.") fmt.Println("Usage: radix_info [flags...] ") fmt.Println("Options:") flag.PrintDefaults() }