-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcline.c
179 lines (162 loc) · 5.88 KB
/
cline.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* @file cline.c
* @author Karin S. Dorman, [email protected]
* @date Tue Mar 20 18:10:33 CDT 2012
*
* Some functions for processing a command line. Note, the programmer must
* provide the definition of a function void fprintf_usage(FILE *, const char
* *, void *) in order to use this code. This function, as its name suggests,
* prints help on command-line usage for the user.
*
* Note: The requirement used to be that the user defined print_usage(const
* char *). To compile older code under that obsolete system, use command-line
* option -DOLD_USAGE with gcc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "cline.h"
/**
* Print error message, usage information, and return a failure code.
*
* @param argv list of comman-line arguments as (unmutable) string constants
* @param i index of argument that could not be parsed
* @param obj void pointer to additional usage information
* @return (simple) error code
*/
int usage_error(const char **argv, int i, void *obj)
{
fprintf(stderr, "ERROR -- incorrect command line usage\n");
if (i >= 0)
fprintf(stderr, "Could not parse command line option '%s'.\n",
argv[i]);
fprintf(stderr, "See correct usage below.\n");
#ifdef OLD_USAGE /* define to compile with older source code */
print_usage(argv[0]);
#else
fprint_usage(stderr, argv[0], obj);
#endif
fprintf(stderr, "\nERROR -- incorrect command line usage\n");
if (i >= 1)
fprintf(stderr, "Could not parse command line option '%s'.\n",
argv[i]);
return EXIT_FAILURE;
} /* usage_error */
/**
* Read an integer from the next argument in the command-line argument
* list. This code avoids some repetition in main()
*
* @param argc the number of arguments
* @param argv the list of command-line arguments strings
* @param i the argument we are to parse at int
* @param obj void pointer to additional usage information
* @return the parsed integer or errno is error
*/
int read_int(int argc, const char **argv, int i, void *obj)
{
int n;
char *ret_ptr;
/* check for end of argument list; assignment to errno BEFORE return */
if (i == argc)
return (errno = usage_error(argv, i-1, obj));
/* It turns out errno is not set to EINVAL (in C99) when the read fails
* as I said in class. The only way to detect failure to read a
* numeric value is to use the second argument. The second argument
* is set to point to the char immediately following the read number.
* If it is the same as the address in the first pointer passed, then
* you know the read was unsuccessful. Note the need to pass a pointer
* to a pointer in order to update the value (address) stored in the
* pointer variable. */
/* n = strtol(argv[i], NULL, 0); */
n = strtol(argv[i], &ret_ptr, 0);
if (errno || ret_ptr == argv[i])
return (errno = usage_error(argv, i, obj));
return n;
} /* read_int */
/**
* Read an positive integer from the next argument in the command-line argument
* list. This code avoids some repetition in main()
*
* @param argc the number of arguments
* @param argv the list of command-line arguments strings
* @param i the argument we are to parse at int
* @param obj void pointer to additional usage information
* @return the parsed unsigned integer or errno is error
*/
unsigned int read_uint(int argc, const char **argv, int i, void *obj)
{
unsigned int n;
char *ret_ptr;
/* check for end of argument list; assignment to errno BEFORE return */
if (i == argc)
return (errno = usage_error(argv, i-1, obj));
/* It turns out errno is not set to EINVAL (in C99) when the read fails
* as I said in class. The only way to detect failure to read a
* numeric value is to use the second argument. The second argument
* is set to point to the char immediately following the read number.
* If it is the same as the address in the first pointer passed, then
* you know the read was unsuccessful. Note the need to pass a pointer
* to a pointer in order to update the value (address) stored in the
* pointer variable. */
/* n = strtol(argv[i], NULL, 0); */
n = strtoul(argv[i], &ret_ptr, 0);
if (errno || ret_ptr == argv[i])
return (errno = usage_error(argv, i, obj));
return n;
} /* read_uint */
/**
* Read a long from the next argument on the command-line.
*
* @param argc the number of arguments
* @param argv the list of command-line arguments strings
* @param i the argument we are to parse at int
* @param obj void pointer to additional usage information
* @return the parsed long or errno is error
*/
long read_long(int argc, const char **argv, int i, void *obj)
{
long n;
char *ret_ptr;
if (i == argc)
return (errno = usage_error(argv, i-1, obj));
n = strtol(argv[i], &ret_ptr, 0);
if (errno || ret_ptr == argv[i])
return (errno = usage_error(argv, i, obj));
return n;
} /* read_long */
/**
* Read a double from the next argument in the command-line argument
* list. This code avoids repetition in main().
*
* @param argc the number of arguments
* @param argv the list of command-line arguments strings
* @param i the argument we are to parse at int
* @param obj void pointer to additional usage information
* @return the parsed integer or errno is error
*/
double read_double(int argc, const char **argv, int i, void *obj)
{
double d;
char *ret_ptr;
if (i==argc)
return (errno = usage_error(argv, i-1, obj));
d = strtod(argv[i], &ret_ptr);
if (errno || ret_ptr == argv[i])
return (errno = usage_error(argv, i, obj));
return d;
} /* read_double */
/**
* Read a char from the next argument on the command-line.
*
* @param argc number of arguments on command-line
* @param argv list of command-line argument strings
* @param i the argument we are to parse as char
* @param obj void pointer to additional usage information
* @return the parsed char or errno is error
*/
char read_char(int argc, const char **argv, int i, void *obj)
{
if (i==argc)
return (errno = usage_error(argv, i-1, obj));
return argv[i][0];
} /* read_char */