Skip to content

Commit a1e51fc

Browse files
authoredMay 15, 2017
Merge pull request #64 from cs50/optional-args
adds support for optional args, with backwards compatibility
2 parents 731a152 + 7c75529 commit a1e51fc

File tree

5 files changed

+175
-91
lines changed

5 files changed

+175
-91
lines changed
 

‎Makefile

+6-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ DESCRIPTION = CS50 Library for C
2525
MAINTAINER = CS50 <sysadmins@cs50.harvard.edu>
2626
NAME = libcs50
2727
OLD_NAMES = lib50-c library50-c
28-
VERSION = 7.2.2
28+
VERSION = 8.0.0
2929

3030
.PHONY: bash
3131
bash:
@@ -34,7 +34,7 @@ bash:
3434
.PHONY: build
3535
build: clean Makefile $(SRC) $(HDR)
3636
mkdir -p "$(INCLUDE_DIR)" "$(LIB_DIR)" "$(MAN_DIR)" "$(BUILD_SRC)"
37-
gcc -c -fPIC -std=c99 -Wall -Werror -o "$(OBJ)" "$(SRC)"
37+
gcc -c -fPIC -std=gnu99 -Wall -o "$(OBJ)" "$(SRC)"
3838
gcc -o "$(LIB_DIR)/libcs50.so" -shared "$(OBJ)"
3939
rm -f "$(OBJ)"
4040
cp "$(HDR)" "$(INCLUDE_DIR)"
@@ -111,7 +111,7 @@ rpm: build
111111
# TODO: improve test suite
112112
.PHONY: test
113113
test: build hackerrank
114-
clang -ggdb3 -I "$(INCLUDE_DIR)" -O0 -std=c99 -Wall -Werror -Wno-deprecated-declarations "$(TESTS_DIR)/eprintf.c" -L "$(LIB_DIR)" -lcs50 -o "$(EPRINTF_EXE)"
115-
clang -I "$(BUILD_DIR)" -std=c99 -Wall -Werror -Wno-deprecated-declarations "$(TESTS_DIR)/hackerrank.c" -o "$(HR_EXE)"
116-
LD_LIBRARY_PATH="$(LIB_DIR)" "$(EPRINTF_EXE)"
117-
"$(HR_EXE)"
114+
#clang -ggdb3 -I "$(INCLUDE_DIR)" -O0 -Wall -Werror -Wno-deprecated-declarations "$(TESTS_DIR)/eprintf.c" -L "$(LIB_DIR)" -lcs50 -o "$(EPRINTF_EXE)"
115+
#clang -I "$(BUILD_DIR)" -Wall -Werror -Wno-deprecated-declarations "$(TESTS_DIR)/hackerrank.c" -o "$(HR_EXE)"
116+
clang -ggdb3 -I "$(INCLUDE_DIR)" -O0 -Wall -Werror -Wno-deprecated-declarations "$(TESTS_DIR)/get_int.c" -L "$(LIB_DIR)" -lcs50 -o "$(BUILD_DIR)"/get_int
117+
LD_LIBRARY_PATH="$(LIB_DIR)" "$(BUILD_DIR)"/get_int

‎src/cs50.c

+90-46
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@
5353
#include "cs50.h"
5454

5555
/**
56-
* Prints an error message, formatted like printf, to standard error, prefixing it with program's
57-
* name as well as the file and line number from which function was called, which a macro is
58-
* expected to provide.
56+
* Prints an error message, formatted like printf, to standard error, prefixing it with
57+
* file name and line number from which function was called (which a macro provides).
5958
*
6059
* This function is not intended to be called directly. Instead, call the macro of the same name,
6160
* which expects fewer arguments.
@@ -84,18 +83,17 @@ void eprintf(const char *file, int line, const char *format, ...)
8483
}
8584

8685
/**
87-
* Reads a line of text from standard input and returns the equivalent
88-
* char; if text does not represent a char, user is prompted to retry.
89-
* Leading and trailing whitespace is ignored. If line can't be read,
90-
* returns CHAR_MAX.
86+
* Prompts user for a line of text from standard input and returns the
87+
* equivalent char; if text is not a single char, user is prompted
88+
* to retry. If line can't be read, returns CHAR_MAX.
9189
*/
92-
char get_char(void)
90+
char get_char(string prompt)
9391
{
9492
// try to get a char from user
9593
while (true)
9694
{
9795
// get line of text, returning CHAR_MAX on failure
98-
string line = get_string();
96+
string line = get_string(prompt);
9997
if (line == NULL)
10098
{
10199
return CHAR_MAX;
@@ -107,24 +105,32 @@ char get_char(void)
107105
{
108106
return c;
109107
}
110-
printf("Retry: ");
108+
109+
// temporarily here for backwards compatibility
110+
if (prompt == NULL)
111+
{
112+
printf("Retry: ");
113+
}
111114
}
112115
}
113-
char (*GetChar)(void) = get_char;
116+
char GetChar(void)
117+
{
118+
return get_char(NULL);
119+
}
114120

115121
/**
116-
* Reads a line of text from standard input and returns the equivalent
117-
* double as precisely as possible; if text does not represent a
118-
* double or if value would cause underflow or overflow, user is
122+
* Prompts user for a line of text from standard input and returns the
123+
* equivalent double as precisely as possible; if text does not represent
124+
* a double or if value would cause underflow or overflow, user is
119125
* prompted to retry. If line can't be read, returns DBL_MAX.
120126
*/
121-
double get_double(void)
127+
double get_double(string prompt)
122128
{
123129
// try to get a double from user
124130
while (true)
125131
{
126132
// get line of text, returning DBL_MAX on failure
127-
string line = get_string();
133+
string line = get_string(prompt);
128134
if (line == NULL)
129135
{
130136
return DBL_MAX;
@@ -145,24 +151,32 @@ double get_double(void)
145151
}
146152
}
147153
}
148-
printf("Retry: ");
154+
155+
// temporarily here for backwards compatibility
156+
if (prompt == NULL)
157+
{
158+
printf("Retry: ");
159+
}
149160
}
150161
}
151-
double (*GetDouble)(void) = get_double;
162+
double GetDouble(void)
163+
{
164+
return get_double(NULL);
165+
}
152166

153167
/**
154-
* Reads a line of text from standard input and returns the equivalent
155-
* float as precisely as possible; if text does not represent a float
156-
* or if value would cause underflow or overflow, user is prompted to
157-
* retry. If line can't be read, returns FLT_MAX.
168+
* Prompts user for a line of text from standard input and returns the
169+
* equivalent float as precisely as possible; if text does not represent
170+
* a float or if value would cause underflow or overflow, user is prompted
171+
* to retry. If line can't be read, returns FLT_MAX.
158172
*/
159-
float get_float(void)
173+
float get_float(string prompt)
160174
{
161175
// try to get a float from user
162176
while (true)
163177
{
164178
// get line of text, returning FLT_MAX on failure
165-
string line = get_string();
179+
string line = get_string(prompt);
166180
if (line == NULL)
167181
{
168182
return FLT_MAX;
@@ -183,24 +197,32 @@ float get_float(void)
183197
}
184198
}
185199
}
186-
printf("Retry: ");
200+
201+
// temporarily here for backwards compatibility
202+
if (prompt == NULL)
203+
{
204+
printf("Retry: ");
205+
}
187206
}
188207
}
189-
float (*GetFloat)(void) = get_float;
208+
float GetFloat(void)
209+
{
210+
return get_float(NULL);
211+
}
190212

191213
/**
192-
* Reads a line of text from standard input and returns it as an
193-
* int in [-2^31, 2^31 - 1), if possible; if text does not represent
194-
* such an int or if value would cause underflow or overflow, user is
195-
* prompted to retry. If line can't be read, returns INT_MAX.
214+
* Prompts user for a line of text from standard input and returns the
215+
* equivalent int; if text does not represent an int in [-2^31, 2^31 - 1)
216+
* or would cause underflow or overflow, user is prompted to retry. If line
217+
* can't be read, returns INT_MAX.
196218
*/
197-
int get_int(void)
219+
int get_int(string prompt)
198220
{
199221
// try to get an int from user
200222
while (true)
201223
{
202224
// get line of text, returning INT_MAX on failure
203-
string line = get_string();
225+
string line = get_string(prompt);
204226
if (line == NULL)
205227
{
206228
return INT_MAX;
@@ -217,18 +239,26 @@ int get_int(void)
217239
return n;
218240
}
219241
}
220-
printf("Retry: ");
242+
243+
// temporarily here for backwards compatibility
244+
if (prompt == NULL)
245+
{
246+
printf("Retry: ");
247+
}
221248
}
222249
}
223-
int (*GetInt)(void) = get_int;
250+
int GetInt(void)
251+
{
252+
return get_int(NULL);
253+
}
224254

225255
/**
226-
* Reads a line of text from standard input and returns an equivalent
227-
* long long in [-2^63, 2^63 - 1), if possible; if text does not
228-
* represent such a long long or if value would cause underflow or overflow,
229-
* user is prompted to retry. If line can't be read, returns LLONG_MAX.
256+
* Prompts user for a line of text from standard input and returns the
257+
* equivalent long long; if text does not represent a long long in
258+
* [-2^63, 2^63 - 1) or would cause underflow or overflow, user is
259+
* prompted to retry. If line can't be read, returns LLONG_MAX.
230260
*/
231-
long long get_long_long(void)
261+
long long get_long_long(string prompt)
232262
{
233263
// try to get a long long from user
234264
while (true)
@@ -251,10 +281,18 @@ long long get_long_long(void)
251281
return n;
252282
}
253283
}
254-
printf("Retry: ");
284+
285+
// temporarily here for backwards compatibility
286+
if (prompt == NULL)
287+
{
288+
printf("Retry: ");
289+
}
255290
}
256291
}
257-
long long (*GetLongLong)(void) = get_long_long;
292+
long long GetLongLong(void)
293+
{
294+
return get_long_long(NULL);
295+
}
258296

259297
/**
260298
* Number of strings allocated by get_string.
@@ -267,14 +305,14 @@ static size_t allocations = 0;
267305
static string *strings = NULL;
268306

269307
/**
270-
* Reads a line of text from standard input and returns it as
271-
* a string (char *), sans trailing line ending. Supports
308+
* Prompts user for a line of text from standard input and returns
309+
* it as a string (char *), sans trailing line ending. Supports
272310
* CR (\r), LF (\n), and CRLF (\r\n) as line endings. If user
273-
* inputs only "\n", returns "", not NULL. Returns NULL upon
274-
* error or no input whatsoever (i.e., just EOF). Stores string
311+
* inputs only a line ending, returns "", not NULL. Returns NULL
312+
* upon error or no input whatsoever (i.e., just EOF). Stores string
275313
* on heap, but library's destructor frees memory on program's exit.
276314
*/
277-
string get_string(void)
315+
string get_string(string prompt)
278316
{
279317
// check whether we have room for another string
280318
if (allocations * sizeof(string) == SIZE_MAX)
@@ -294,6 +332,12 @@ string get_string(void)
294332
// character read or EOF
295333
int c;
296334

335+
// prompt user
336+
if (prompt != NULL)
337+
{
338+
printf("%s", prompt);
339+
}
340+
297341
// iteratively get characters from standard input, checking for CR (Mac OS), LF (Linux), and CRLF (Windows)
298342
while ((c = fgetc(stdin)) != '\r' && c != '\n' && c != EOF)
299343
{

‎src/cs50.h

+68-38
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,28 @@
4646
#include <stdbool.h>
4747
#include <stdlib.h>
4848

49+
/**
50+
* Temporarily used to make arguments to get_* (but not Get*) optional.
51+
* Inspired by https://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/.
52+
*/
53+
#ifdef __GNUC__
54+
#define _ARGS(_0, _1, _2, ...) _2
55+
#define ARGS(...) _ARGS(, ##__VA_ARGS__, 1, 0)
56+
#define ARG_0(NAME) NULL
57+
#define ARG_1(NAME, a) a
58+
#define __ZERO_OR_ONE_ARG(NAME, N, ...) ARG_ ## N (NAME, ##__VA_ARGS__)
59+
#define _ZERO_OR_ONE_ARG(NAME, N, ...) __ZERO_OR_ONE_ARG(NAME, N, ##__VA_ARGS__)
60+
#define ZERO_OR_ONE_ARG(NAME, ...) NAME(_ZERO_OR_ONE_ARG(NAME, ARGS(__VA_ARGS__), ##__VA_ARGS__))
61+
#endif
62+
4963
/**
5064
* Our own data type for string variables.
5165
*/
5266
typedef char *string;
5367

5468
/**
55-
* Prints an error message, formatted like printf, to standard error, prefixing it with program's
56-
* name as well as the file and line number from which function was called, which a macro is
57-
* expected to provide.
69+
* Prints an error message, formatted like printf, to standard error, prefixing it with
70+
* file name and line number from which function was called (which a macro provides).
5871
*
5972
* This function is not intended to be called directly. Instead, call the macro of the same name,
6073
* which expects fewer arguments.
@@ -72,59 +85,76 @@ void eprintf(const char *file, int line, const char *format, ...) __attribute__(
7285
#define eprintf(format, ...) eprintf(__FILE__, __LINE__, format, ##__VA_ARGS__)
7386

7487
/**
75-
* Reads a line of text from standard input and returns the equivalent
76-
* char; if text does not represent a char, user is prompted to retry.
77-
* Leading and trailing whitespace is ignored. If line can't be read,
78-
* returns CHAR_MAX.
88+
* Prompts user for a line of text from standard input and returns the
89+
* equivalent char; if text is not a single char, user is prompted
90+
* to retry. If line can't be read, returns CHAR_MAX.
7991
*/
80-
char get_char(void);
81-
extern char (*GetChar)(void);
92+
char get_char(string prompt);
93+
char GetChar(void) __attribute__((deprecated));
94+
#ifdef __GNUC__
95+
#define get_char(...) ZERO_OR_ONE_ARG(get_char, ##__VA_ARGS__)
96+
#endif
8297

8398
/**
84-
* Reads a line of text from standard input and returns the equivalent
85-
* double as precisely as possible; if text does not represent a
86-
* double or if value would cause underflow or overflow, user is
99+
* Prompts user for a line of text from standard input and returns the
100+
* equivalent double as precisely as possible; if text does not represent
101+
* a double or if value would cause underflow or overflow, user is
87102
* prompted to retry. If line can't be read, returns DBL_MAX.
88103
*/
89-
double get_double(void);
90-
extern double (*GetDouble)(void);
104+
double get_double(string prompt);
105+
double GetDouble(void) __attribute__((deprecated));
106+
#ifdef __GNUC__
107+
#define get_double(...) ZERO_OR_ONE_ARG(get_double, ##__VA_ARGS__)
108+
#endif
91109

92110
/**
93-
* Reads a line of text from standard input and returns the equivalent
94-
* float as precisely as possible; if text does not represent a float
95-
* or if value would cause underflow or overflow, user is prompted to
96-
* retry. If line can't be read, returns FLT_MAX.
111+
* Prompts user for a line of text from standard input and returns the
112+
* equivalent float as precisely as possible; if text does not represent
113+
* a float or if value would cause underflow or overflow, user is prompted
114+
* to retry. If line can't be read, returns FLT_MAX.
97115
*/
98-
float get_float(void);
99-
extern float (*GetFloat)(void);
116+
float get_float(string prompt);
117+
float GetFloat(void) __attribute__((deprecated));
118+
#ifdef __GNUC__
119+
#define get_float(...) ZERO_OR_ONE_ARG(get_float, ##__VA_ARGS__)
120+
#endif
100121

101122
/**
102-
* Reads a line of text from standard input and returns it as an
103-
* int in [-2^31, 2^31 - 1), if possible; if text does not represent
104-
* such an int or if value would cause underflow or overflow, user is
105-
* prompted to retry. If line can't be read, returns INT_MAX.
123+
* Prompts user for a line of text from standard input and returns the
124+
* equivalent int; if text does not represent an int in [-2^31, 2^31 - 1)
125+
* or would cause underflow or overflow, user is prompted to retry. If line
126+
* can't be read, returns INT_MAX.
106127
*/
107-
int get_int(void);
108-
extern int (*GetInt)(void);
128+
int get_int(string prompt);
129+
int GetInt(void) __attribute__((deprecated));
130+
#ifdef __GNUC__
131+
#define get_int(...) ZERO_OR_ONE_ARG(get_int, ##__VA_ARGS__)
132+
#endif
109133

110134
/**
111-
* Reads a line of text from standard input and returns an equivalent
112-
* long long in [-2^63, 2^63 - 1), if possible; if text does not
113-
* represent such a long long or if value would cause underflow or overflow,
114-
* user is prompted to retry. If line can't be read, returns LLONG_MAX.
135+
* Prompts user for a line of text from standard input and returns the
136+
* equivalent long long; if text does not represent a long long in
137+
* [-2^63, 2^63 - 1) or would cause underflow or overflow, user is
138+
* prompted to retry. If line can't be read, returns LLONG_MAX.
115139
*/
116-
long long get_long_long(void);
117-
extern long long (*GetLongLong)(void);
140+
long long get_long_long(string prompt);
141+
long long GetLongLong(void) __attribute__((deprecated));
142+
#ifdef __GNUC__
143+
#define get_long_long(...) ZERO_OR_ONE_ARG(get_long_long, ##__VA_ARGS__)
144+
#endif
118145

119146
/**
120-
* Reads a line of text from standard input and returns it as
121-
* a string (char *), sans trailing line ending. Supports
147+
* Prompts user for a line of text from standard input and returns
148+
* it as a string (char *), sans trailing line ending. Supports
122149
* CR (\r), LF (\n), and CRLF (\r\n) as line endings. If user
123-
* inputs only "\n", returns "", not NULL. Returns NULL upon
124-
* error or no input whatsoever (i.e., just EOF). Stores string
150+
* inputs only a line ending, returns "", not NULL. Returns NULL
151+
* upon error or no input whatsoever (i.e., just EOF). Stores string
125152
* on heap, but library's destructor frees memory on program's exit.
126153
*/
127-
string get_string(void);
128-
string GetString(void);
154+
string get_string(string prompt);
155+
string GetString(void) __attribute__((deprecated));
156+
#ifdef __GNUC__
157+
#define get_string(...) ZERO_OR_ONE_ARG(get_string, ##__VA_ARGS__)
158+
#endif
129159

130160
#endif

‎tests/eprintf.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
#include <stdio.h>
12
#include "cs50.h"
2-
#include "stdio.h"
33

44
int main(void)
55
{

‎tests/get_int.c

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <stdio.h>
2+
#include "cs50.h"
3+
4+
int main(void)
5+
{
6+
int i = get_int();
7+
printf("%i\n", i);
8+
int j = get_int("Foo: ");
9+
printf("%i\n", j);
10+
}

0 commit comments

Comments
 (0)
Please sign in to comment.