diff --git a/.gitignore b/.gitignore index 9cf173f..0385c81 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ build/ debian/changelog debian/docs/ +debian/files +debian/libcs50 +debian/*.log hackerrank/ libcs50-* libcs50_* diff --git a/.travis.yml b/.travis.yml index 87fb8e5..149735d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ dist: trusty sudo: required +branches: + except: "/^v\\d/" before_install: - sudo apt-get install build-essential debhelper devscripts dh-make lintian - gem install asciidoctor diff --git a/Makefile b/Makefile index 298c6fd..beb5637 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := 8.0.3 +VERSION := 8.0.4 # soname - libcs50.so. SONAME := libcs50.so.$(shell echo $(VERSION) | head -c 1) @@ -8,7 +8,7 @@ DESTDIR ?= /usr/local .PHONY: build build: clean - $(CC) -c -fPIC -std=gnu99 -Wall -o cs50.o src/cs50.c + $(CC) -c -fPIC -std=c99 -Wall -o cs50.o src/cs50.c $(CC) -shared -Wl,-soname,$(SONAME) -o libcs50.so.$(VERSION) cs50.o rm -f cs50.o ln -s libcs50.so.$(VERSION) $(SONAME) @@ -37,7 +37,7 @@ docs: deb: build docs @echo "libcs50 ($(VERSION)-0ubuntu1) trusty; urgency=low" > debian/changelog @echo " * v$(VERSION)" >> debian/changelog - @echo " -- CS50 Sysadmins $$(date --rfc-2822)" >> debian/changelog + @echo " -- CS50 Sysadmins $$(date --rfc-2822)" >> debian/changelog mkdir -p libcs50-$(VERSION)/usr rsync -a build/* libcs50-$(VERSION)/usr --exclude=hack tar -cvzf libcs50_$(VERSION).orig.tar.gz libcs50-$(VERSION) diff --git a/debian/libcs50.postinst.debhelper b/debian/libcs50.postinst.debhelper new file mode 100644 index 0000000..3d89d3e --- /dev/null +++ b/debian/libcs50.postinst.debhelper @@ -0,0 +1,5 @@ +# Automatically added by dh_makeshlibs +if [ "$1" = "configure" ]; then + ldconfig +fi +# End automatically added section diff --git a/debian/libcs50.postrm.debhelper b/debian/libcs50.postrm.debhelper new file mode 100644 index 0000000..7f44047 --- /dev/null +++ b/debian/libcs50.postrm.debhelper @@ -0,0 +1,5 @@ +# Automatically added by dh_makeshlibs +if [ "$1" = "remove" ]; then + ldconfig +fi +# End automatically added section diff --git a/debian/libcs50.substvars b/debian/libcs50.substvars new file mode 100644 index 0000000..478a80a --- /dev/null +++ b/debian/libcs50.substvars @@ -0,0 +1,2 @@ +shlibs:Depends=libc6 (>= 2.3) +misc:Depends= diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 0000000..e80647c --- /dev/null +++ b/debian/postinst @@ -0,0 +1,39 @@ +#!/bin/sh +# postinst script for libcs50 +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 0000000..c591843 --- /dev/null +++ b/debian/postrm @@ -0,0 +1,37 @@ +#!/bin/sh +# postrm script for libcs50 +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/src/cs50.c b/src/cs50.c index af0c0fb..3769eee 100644 --- a/src/cs50.c +++ b/src/cs50.c @@ -4,9 +4,7 @@ * * Based on Eric Roberts' genlib.c and simpio.c. * - * Copyright (c) 2017, - * Glenn Holloway - * David J. Malan + * Copyright (c) 2017. * All rights reserved. * * BSD 3-Clause License @@ -52,6 +50,15 @@ #include "cs50.h" +// temporarily here for backwards compatibility +#undef get_char +#undef get_double +#undef get_float +#undef get_int +#undef get_long_long +#undef get_string +#define null (&(struct prompt) {0}) + /** * Prints an error message, formatted like printf, to standard error, prefixing it with * file name and line number from which function was called (which a macro provides). @@ -59,7 +66,7 @@ * This function is not intended to be called directly. Instead, call the macro of the same name, * which expects fewer arguments. * - * Inspired by http://www.gnu.org/software/libc/manual/html_node/Variable-Arguments-Output.html + * Inspired by http://www.gnu.org/software/libc/manual/html_node/Variable-Arguments-Output.html, * http://www.gnu.org/software/libc/manual/html_node/Error-Messages.html#Error-Messages, and * https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html. */ @@ -87,13 +94,13 @@ void eprintf(const char *file, int line, const char *format, ...) * equivalent char; if text is not a single char, user is prompted * to retry. If line can't be read, returns CHAR_MAX. */ -char get_char(string prompt) +char get_char(struct prompt *p) { // try to get a char from user while (true) { // get line of text, returning CHAR_MAX on failure - string line = get_string(prompt); + string line = get_string(p); if (line == NULL) { return CHAR_MAX; @@ -107,7 +114,7 @@ char get_char(string prompt) } // temporarily here for backwards compatibility - if (prompt == NULL) + if (p->prompt == NULL) { printf("Retry: "); } @@ -115,7 +122,7 @@ char get_char(string prompt) } char GetChar(void) { - return get_char(NULL); + return get_char(null); } /** @@ -124,13 +131,13 @@ char GetChar(void) * a double or if value would cause underflow or overflow, user is * prompted to retry. If line can't be read, returns DBL_MAX. */ -double get_double(string prompt) +double get_double(struct prompt *p) { // try to get a double from user while (true) { // get line of text, returning DBL_MAX on failure - string line = get_string(prompt); + string line = get_string(p); if (line == NULL) { return DBL_MAX; @@ -153,7 +160,7 @@ double get_double(string prompt) } // temporarily here for backwards compatibility - if (prompt == NULL) + if (p->prompt == NULL) { printf("Retry: "); } @@ -161,7 +168,7 @@ double get_double(string prompt) } double GetDouble(void) { - return get_double(NULL); + return get_double(null); } /** @@ -170,13 +177,13 @@ double GetDouble(void) * a float or if value would cause underflow or overflow, user is prompted * to retry. If line can't be read, returns FLT_MAX. */ -float get_float(string prompt) +float get_float(struct prompt *p) { // try to get a float from user while (true) { // get line of text, returning FLT_MAX on failure - string line = get_string(prompt); + string line = get_string(p); if (line == NULL) { return FLT_MAX; @@ -199,7 +206,7 @@ float get_float(string prompt) } // temporarily here for backwards compatibility - if (prompt == NULL) + if (p->prompt == NULL) { printf("Retry: "); } @@ -207,7 +214,7 @@ float get_float(string prompt) } float GetFloat(void) { - return get_float(NULL); + return get_float(null); } /** @@ -216,13 +223,13 @@ float GetFloat(void) * or would cause underflow or overflow, user is prompted to retry. If line * can't be read, returns INT_MAX. */ -int get_int(string prompt) +int get_int(struct prompt *p) { // try to get an int from user while (true) { // get line of text, returning INT_MAX on failure - string line = get_string(prompt); + string line = get_string(p); if (line == NULL) { return INT_MAX; @@ -241,7 +248,7 @@ int get_int(string prompt) } // temporarily here for backwards compatibility - if (prompt == NULL) + if (p->prompt == NULL) { printf("Retry: "); } @@ -249,7 +256,7 @@ int get_int(string prompt) } int GetInt(void) { - return get_int(NULL); + return get_int(null); } /** @@ -258,13 +265,13 @@ int GetInt(void) * [-2^63, 2^63 - 1) or would cause underflow or overflow, user is * prompted to retry. If line can't be read, returns LLONG_MAX. */ -long long get_long_long(string prompt) +long long get_long_long(struct prompt *p) { // try to get a long long from user while (true) { // get line of text, returning LLONG_MAX on failure - string line = get_string(prompt); + string line = get_string(p); if (line == NULL) { return LLONG_MAX; @@ -283,7 +290,7 @@ long long get_long_long(string prompt) } // temporarily here for backwards compatibility - if (prompt == NULL) + if (p->prompt == NULL) { printf("Retry: "); } @@ -291,7 +298,7 @@ long long get_long_long(string prompt) } long long GetLongLong(void) { - return get_long_long(NULL); + return get_long_long(null); } /** @@ -312,7 +319,7 @@ static string *strings = NULL; * upon error or no input whatsoever (i.e., just EOF). Stores string * on heap, but library's destructor frees memory on program's exit. */ -string get_string(string prompt) +string get_string(struct prompt *p) { // check whether we have room for another string if (allocations * sizeof(string) == SIZE_MAX) @@ -333,9 +340,9 @@ string get_string(string prompt) int c; // prompt user - if (prompt != NULL) + if (p->prompt != NULL) { - printf("%s", prompt); + printf("%s", p->prompt); } // iteratively get characters from standard input, checking for CR (Mac OS), LF (Linux), and CRLF (Windows) diff --git a/src/cs50.h b/src/cs50.h index 18a69b1..0236da5 100644 --- a/src/cs50.h +++ b/src/cs50.h @@ -4,9 +4,7 @@ * * Based on Eric Roberts' genlib.c and simpio.c. * - * Copyright (c) 2017, - * Glenn Holloway - * David J. Malan + * Copyright (c) 2017. * All rights reserved. * * BSD 3-Clause License @@ -47,23 +45,18 @@ #include /** - * Temporarily used to make arguments to get_* (but not Get*) optional. - * Inspired by https://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/. + * Our own data type for string variables. */ -#ifdef __GNUC__ -#define _ARGS(_0, _1, _2, ...) _2 -#define ARGS(...) _ARGS(, ##__VA_ARGS__, 1, 0) -#define ARG_0(NAME) NULL -#define ARG_1(NAME, a) a -#define __ZERO_OR_ONE_ARG(NAME, N, ...) ARG_ ## N (NAME, ##__VA_ARGS__) -#define _ZERO_OR_ONE_ARG(NAME, N, ...) __ZERO_OR_ONE_ARG(NAME, N, ##__VA_ARGS__) -#define ZERO_OR_ONE_ARG(NAME, ...) NAME(_ZERO_OR_ONE_ARG(NAME, ARGS(__VA_ARGS__), ##__VA_ARGS__)) -#endif +typedef char *string; /** - * Our own data type for string variables. + * Temporarily used to make arguments to get_* (but not Get*) optional. */ -typedef char *string; +struct prompt +{ + int _sentinel; + string prompt; +}; /** * Prints an error message, formatted like printf, to standard error, prefixing it with @@ -89,11 +82,9 @@ void eprintf(const char *file, int line, const char *format, ...) __attribute__( * equivalent char; if text is not a single char, user is prompted * to retry. If line can't be read, returns CHAR_MAX. */ -char get_char(string prompt); +char get_char(struct prompt *p); char GetChar(void) __attribute__((deprecated)); -#ifdef __GNUC__ -#define get_char(...) ZERO_OR_ONE_ARG(get_char, ##__VA_ARGS__) -#endif +#define get_char(...) get_char(&(struct prompt) {0, __VA_ARGS__}) /** * Prompts user for a line of text from standard input and returns the @@ -101,11 +92,9 @@ char GetChar(void) __attribute__((deprecated)); * a double or if value would cause underflow or overflow, user is * prompted to retry. If line can't be read, returns DBL_MAX. */ -double get_double(string prompt); +double get_double(struct prompt *p); double GetDouble(void) __attribute__((deprecated)); -#ifdef __GNUC__ -#define get_double(...) ZERO_OR_ONE_ARG(get_double, ##__VA_ARGS__) -#endif +#define get_double(...) get_double(&(struct prompt) {0, __VA_ARGS__}) /** * Prompts user for a line of text from standard input and returns the @@ -113,11 +102,9 @@ double GetDouble(void) __attribute__((deprecated)); * a float or if value would cause underflow or overflow, user is prompted * to retry. If line can't be read, returns FLT_MAX. */ -float get_float(string prompt); +float get_float(struct prompt *p); float GetFloat(void) __attribute__((deprecated)); -#ifdef __GNUC__ -#define get_float(...) ZERO_OR_ONE_ARG(get_float, ##__VA_ARGS__) -#endif +#define get_float(...) get_float(&(struct prompt) {0, __VA_ARGS__}) /** * Prompts user for a line of text from standard input and returns the @@ -125,11 +112,9 @@ float GetFloat(void) __attribute__((deprecated)); * or would cause underflow or overflow, user is prompted to retry. If line * can't be read, returns INT_MAX. */ -int get_int(string prompt); +int get_int(struct prompt *p); int GetInt(void) __attribute__((deprecated)); -#ifdef __GNUC__ -#define get_int(...) ZERO_OR_ONE_ARG(get_int, ##__VA_ARGS__) -#endif +#define get_int(...) get_int(&(struct prompt) {0, __VA_ARGS__}) /** * Prompts user for a line of text from standard input and returns the @@ -137,11 +122,9 @@ int GetInt(void) __attribute__((deprecated)); * [-2^63, 2^63 - 1) or would cause underflow or overflow, user is * prompted to retry. If line can't be read, returns LLONG_MAX. */ -long long get_long_long(string prompt); +long long get_long_long(struct prompt *p); long long GetLongLong(void) __attribute__((deprecated)); -#ifdef __GNUC__ -#define get_long_long(...) ZERO_OR_ONE_ARG(get_long_long, ##__VA_ARGS__) -#endif +#define get_long_long(...) get_long_long(&(struct prompt) {0, __VA_ARGS__}) /** * Prompts user for a line of text from standard input and returns @@ -151,10 +134,8 @@ long long GetLongLong(void) __attribute__((deprecated)); * upon error or no input whatsoever (i.e., just EOF). Stores string * on heap, but library's destructor frees memory on program's exit. */ -string get_string(string prompt); +string get_string(struct prompt *p); string GetString(void) __attribute__((deprecated)); -#ifdef __GNUC__ -#define get_string(...) ZERO_OR_ONE_ARG(get_string, ##__VA_ARGS__) -#endif +#define get_string(...) get_string(&(struct prompt) {0, __VA_ARGS__}) #endif