├── .gitignore ├── README.md ├── test └── get_int.cpp ├── src ├── cs50.cpp └── cs50.hpp └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.gitignore 3 | build/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #TODO: 2 | 3 | * Decide if read errors should throw exceptions 4 | -------------------------------------------------------------------------------- /test/get_int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "cs50.h" 4 | 5 | int main() 6 | { 7 | int i = cs50::get_int(); 8 | std::cout << i << std::endl; 9 | } 10 | -------------------------------------------------------------------------------- /src/cs50.cpp: -------------------------------------------------------------------------------- 1 | #include "cs50.hpp" 2 | 3 | struct BufferingDisabler 4 | { 5 | BufferingDisabler() 6 | { 7 | // Should we make EOF/read errors exceptions? 8 | //std::cin.exceptions(std::ios_base::eofbit | std::ios_base::badbit); 9 | std::cout.setf(std::ios::unitbuf); 10 | } 11 | }; 12 | 13 | static BufferingDisabler _disable_buffering; 14 | -------------------------------------------------------------------------------- /src/cs50.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace cs50 7 | { 8 | template 9 | T get(std::string const& prompt) 10 | { 11 | T i; 12 | for (;;) 13 | { 14 | auto stream = std::istringstream{get(prompt)}; 15 | 16 | // Read value of type T from stream 17 | if (stream >> std::noskipws >> i ) 18 | { 19 | // Ensure `i` is not the maximum value of its type and that there 20 | // are no more characters in the stream after reading it 21 | if (i != std::numeric_limits::max() && !stream.rdbuf()->in_avail()) 22 | { 23 | return i; 24 | } 25 | } 26 | 27 | // Return maximum value of type T if there was an error/EOF when 28 | // reading stdin 29 | else if (std::cin.bad() || std::cin.eof()) 30 | { 31 | return std::numeric_limits::max(); 32 | } 33 | } 34 | } 35 | 36 | // Specialized get template for strings 37 | template<> 38 | std::string get(std::string const& prompt) 39 | { 40 | std::cout << prompt; 41 | for (;;) 42 | { 43 | std::string s; 44 | if (std::getline(std::cin, s)) 45 | { 46 | // Remove trailing \r if present 47 | if (s.size() && s.back() == '\r') 48 | { 49 | s.pop_back(); 50 | } 51 | return s; 52 | } 53 | else 54 | { 55 | return std::string{}; 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # useful paths 2 | CC = g++ 3 | SRC_DIR = src 4 | HDR = $(SRC_DIR)/cs50.hpp 5 | SRC = $(SRC_DIR)/cs50.cpp 6 | 7 | BUILD_DIR = build 8 | OBJ = $(BUILD_DIR)/cs50++.o 9 | USR_DIR = $(BUILD_DIR)/usr 10 | INCLUDE_DIR = $(USR_DIR)/include 11 | LIB_DIR = $(USR_DIR)/lib 12 | BUILD_SRC = $(USR_DIR)/src 13 | 14 | # deb package info 15 | DESCRIPTION = CS50 Library for C++ 16 | MAINTAINER = CS50 17 | NAME = libcs50++ 18 | VERSION = 1.0.0 19 | 20 | .PHONY: bash 21 | bash: 22 | docker run -i --rm -t -v "$(PWD):/root" cs50/cli 23 | 24 | .PHONY: build 25 | build: clean Makefile $(SRC) $(HDR) 26 | mkdir -p "$(INCLUDE_DIR)" "$(LIB_DIR)" "$(BUILD_SRC)" 27 | $(CC) -c -fPIC -std=c++11 -Wall -o "$(OBJ)" "$(SRC)" 28 | $(CC) -o "$(LIB_DIR)/libcs50++.so" -shared "$(OBJ)" 29 | rm -f "$(OBJ)" 30 | cp "$(HDR)" "$(INCLUDE_DIR)" 31 | cp "$(SRC)" "$(BUILD_SRC)" 32 | #cp -r docs/* "$(MAN_DIR)" 33 | find "$(BUILD_DIR)" -type d -exec chmod 0755 {} + 34 | find "$(BUILD_DIR)" -type f -exec chmod 0644 {} + 35 | 36 | .PHONY: clean 37 | clean: 38 | rm -rf "$(BUILD_DIR)" 39 | 40 | .PHONY: deb 41 | deb: build 42 | fpm \ 43 | -C "$(BUILD_DIR)" \ 44 | -m "$(MAINTAINER)" \ 45 | -n "$(NAME)" \ 46 | -p "$(BUILD_DIR)" \ 47 | -s dir \ 48 | -t deb \ 49 | -v "$(VERSION)" \ 50 | --conflicts "$(NAME) (<< $(VERSION))" \ 51 | --deb-no-default-config-files \ 52 | --depends c-compiler \ 53 | --description "$(DESCRIPTION)" \ 54 | --provides "$(NAME)" \ 55 | --replaces "$(NAME) (<= $(VERSION))" \ 56 | usr 57 | 58 | .PHONY: hackerrank 59 | hackerrank: build 60 | cat "$(HDR)" > "$(HR_HDR)" 61 | echo "\n#ifndef _CS50_C\n#define _CS50_C\n" >> "$(HR_HDR)" 62 | cat "$(SRC)" >> "$(HR_HDR)" 63 | echo "\n#endif" >> "$(HR_HDR)" 64 | 65 | .PHONY: install 66 | install: build 67 | cp "$(INCLUDE_DIR)"/* /usr/include 68 | cp "$(LIB_DIR)"/* /usr/lib 69 | 70 | # TODO: add dependencies 71 | .PHONY: pacman 72 | pacman: build 73 | rm -f "$(NAME)-$(VERSION)-"*.pkg.tar.xz 74 | fpm \ 75 | -C "$(BUILD_DIR)" \ 76 | -m "$(MAINTAINER)" \ 77 | -n "$(NAME)" \ 78 | -p "$(BUILD_DIR)" \ 79 | -s dir \ 80 | -t pacman \ 81 | -v "$(VERSION)" \ 82 | --description "$(DESCRIPTION)" \ 83 | usr 84 | 85 | # TODO: add dependencies 86 | .PHONY: rpm 87 | rpm: build 88 | rm -f "$(NAME)-$(VERSION)-"*.rpm 89 | fpm \ 90 | -C "$(BUILD_DIR)" \ 91 | -m "$(MAINTAINER)" \ 92 | -n "$(NAME)" \ 93 | -p "$(BUILD_DIR)" \ 94 | -s dir \ 95 | -t rpm \ 96 | -v "$(VERSION)" \ 97 | --description "$(DESCRIPTION)" \ 98 | usr 99 | --------------------------------------------------------------------------------