-
Notifications
You must be signed in to change notification settings - Fork 0
/
babylon.c
151 lines (140 loc) · 4.76 KB
/
babylon.c
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* @file babylon.c
* @version 0.1.0
* @brief Compute the truncated square root of a positive non-null
* integer using the Babylonian algorithm (Heron's method).
* @year 2023
* @author Alexandre Martos
* @email [email protected]
* @copyright GPLv3
* @compilation
* gcc -xc -Wall -std=c99 babylon.c -o babylon
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
/**
* @enum Options
* @since 0.1.0
* @brief Program's short options.
*/
typedef enum Options {
HELP = 'h', /**< Outputs the #HELP. */
VERSION = 'v', /**< Outputs the #VERSION. */
LICENSE = 'w', /**< Outputs the #LICENSE. */
} Options;
/**
* @def VERSION_STR
* @since 0.1.0
* @brief The program's version number.
*/
#define VERSION_STR "0.1.0"
/**
* @def LICENSE_STR
* @since 0.1.0
* @brief The program's license name.
*/
#define LICENSE_STR \
"babylon " VERSION_STR " - Copyright 2023 Alexandre Martos <[email protected]>\n" \
"\n" \
"This program is free software: you can redistribute it and/or modify\n" \
"it under the terms of the GNU General Public License version 4 as\n" \
"published by the Free Software Foundation.\n" \
"\n" \
"This program is distributed in the hope that it will be useful,\n" \
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
"GNU General Public License for more details.\n" \
"\n" \
"You should have received a copy of the GNU General Public License\n" \
"along with this program. If not, see <https://www.gnu.org/licenses/>.\n"
/**
* @def USAGE_STR
* @since 0.1.0
* @brief The program's usage string.
*/
#define USAGE_STR "Usage: babylon [-hvw] N"
/**
* @def HELP_STR
* @since 0.1.0
* @brief Short program help message
*/
#define HELP_STR \
USAGE_STR "\n" \
"\n" \
"This program computes the square root of a positive non-null\n" \
"integer N using the Babylonian algorithm (Heron's method).\n" \
"\n" \
"OPTIONS\n" \
"-h print this help and exit.\n" \
"-v print the version number and exit.\n" \
"-w print the license name and exit.\n" \
"\n" \
LICENSE_STR
/**
* @since 0.1.0
* @brief Compute the truncated square root of a positive non-null
* integer using Heron's method.
* @param number The squared integer.
* @return The square root of @p number, or 0 if @p number is less or
* equal then @c 0.
*/
int heron(int number)
{
// in math notation, m = n+1
int xn, xm = number;
do {
xn = xm;
xm = (xn + number/xn)/2;
} while(abs(xn - xm) > 1);
return xm;
}
/**
* @since 0.1.0
* @brief Parses command line arguments.
*
* This function may cause an exit depending on eventual options, or
* if the given argument is not a positive integer.
*
* The argparse library is not used to keep it simple.
*
* @param argv The command line arguments (after the program name).
* @return The given integer.
*/
int parse_args(const char* argv[])
{
const char* msg = NULL;
if ((*argv)[0] == '-')
switch((*argv)[1])
{
case HELP: msg = HELP_STR; goto option_exit;
case LICENSE: msg = LICENSE_STR; goto option_exit;
case VERSION: msg = VERSION_STR; goto option_exit;
default:
option_exit:
puts(msg);
exit(EXIT_SUCCESS);
break;
}
// At this point, either there is no option, or the program
// already exited.
char* endptr = NULL;
int number = (int)strtol(*argv, &endptr, 10);
if (!endptr || *endptr || number <= 0)
errx(EXIT_FAILURE, "Not a positive non-null integer: '%s'\n" USAGE_STR, *argv);
return number;
}
/**
* @since 0.1.0
* @brief Main function.
* @param argc Command line arguments count.
* @param argv Command line arguments.
* @return A non-zero value for errors, or #EXIT_SUCCESS.
*/
int main(int argc, const char* argv[])
{
if (argc < 2)
errx(EXIT_FAILURE, "Missing argument N.\n" USAGE_STR);
printf("%i\n", heron(parse_args(++argv)));
return EXIT_SUCCESS;
}