summaryrefslogtreecommitdiff
path: root/args.go
blob: 38a3b1a85bd1ced1fe1408d61341ee6130c187a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* This script is part of radix_info.
   Copyright (C) 2023  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 <https://www.gnu.org/licenses/>.
*/

package main

import (
	"errors"
	"flag"
	"fmt"
	"strconv"
)

const ProgramVersion = "1.0.0-rc.1"

// The arguments to this program
type args struct {
	Radix          uint
	Compact        bool
	FullMap        bool
	ExactMTCLarge  bool
	TotativeDigits bool
	DigitMapOnly   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.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...] <radix>")
	fmt.Println("Options:")
	flag.PrintDefaults()
}