├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── dbg.h ├── ex0 ├── index.html └── lecture.md ├── ex1 ├── ex1.c ├── ex1_zed.c ├── index.html └── lecture.md ├── ex10 ├── Makefile ├── README.me ├── ex10.c ├── index.html └── lecture.md ├── ex11 ├── Makefile ├── README.me ├── ex11.c ├── index.html └── lecture.md ├── ex12 ├── Makefile ├── README.me ├── ex12.c ├── index.html └── lecture.md ├── ex13 ├── Makefile ├── README.me ├── ex13.c ├── index.html └── lecture.md ├── ex14 ├── Makefile ├── README.me ├── ex14.c ├── index.html └── lecture.md ├── ex15 ├── Makefile ├── README.me ├── ex15.c ├── index.html └── lecture.md ├── ex16 ├── Makefile ├── README.me ├── ex16.c ├── index.html └── lecture.md ├── ex17 ├── Makefile ├── README.me ├── ex17.c ├── index.html └── lecture.md ├── ex18 ├── Makefile ├── README.me ├── ex18.c ├── index.html └── lecture.md ├── ex19 ├── Makefile ├── README.me ├── dbg.h ├── ex19.c ├── index.html └── lecture.md ├── ex2 ├── Makefile ├── README.me ├── ex1.c ├── index.html └── lecture.md ├── ex20 ├── Makefile ├── README.me ├── dbg.h ├── ex20.c ├── ex20_obo.c ├── index.html ├── lecture.md └── test.sh ├── ex21 ├── Makefile ├── README.me ├── index.html └── lecture.md ├── ex22 ├── Makefile ├── README.me ├── dbg.h ├── ex22.c ├── ex22.h ├── ex22_main.c ├── index.html └── lecture.md ├── ex23 ├── Makefile ├── README.me ├── dbg.h ├── ex23.c ├── index.html └── lecture.md ├── ex24 ├── Makefile ├── README.me ├── dbg.h ├── ex24.c ├── index.html └── lecture.md ├── ex25 ├── Makefile ├── README.me ├── dbg.h ├── ex25.c ├── index.html └── lecture.md ├── ex26 ├── README.me ├── index.html ├── lecture.md ├── logfind.1 │ ├── Makefile │ ├── dbg.h │ └── logfind.c ├── logfind.2 │ ├── Makefile │ ├── dbg.h │ └── logfind.c ├── logfind.3 │ ├── .logfind │ ├── Makefile │ ├── dbg.h │ └── logfind.c ├── logfind.4 │ ├── .logfind │ ├── Makefile │ ├── dbg.h │ └── logfind.c └── logfind.5 │ ├── .logfind │ ├── Makefile │ ├── dbg.h │ └── logfind.c ├── ex27 ├── README.me ├── index.html ├── lecture.md └── logfind.5 │ ├── .logfind │ ├── Makefile │ ├── dbg.h │ └── logfind.c ├── ex28 ├── README.me ├── c-skeleton │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── src │ │ ├── dbg.h │ │ └── libex29.c │ └── tests │ │ ├── libex29_tests.c │ │ ├── minunit.h │ │ └── runtests.sh ├── index.html └── lecture.md ├── ex29 ├── README.me ├── dbg.h ├── ex29.c ├── index.html ├── lecture.md └── libex29.c ├── ex3 ├── Makefile ├── README.me ├── ex3.c ├── index.html └── lecture.md ├── ex30 ├── README.me ├── ex30.c ├── index.html └── lecture.md ├── ex31 ├── README.me ├── ex31.c ├── index.html └── lecture.md ├── ex32 ├── README.me ├── index.html └── lecture.md ├── ex33 ├── README.me ├── index.html └── lecture.md ├── ex34 ├── README.me ├── index.html └── lecture.md ├── ex35 ├── README.me ├── ex35.c ├── index.html └── lecture.md ├── ex36 ├── README.me ├── ex36.c ├── index.html └── lecture.md ├── ex37 ├── README.me ├── index.html └── lecture.md ├── ex38 ├── README.me ├── index.html └── lecture.md ├── ex39 ├── README.me ├── index.html └── lecture.md ├── ex4 ├── README.me ├── ex4.c ├── index.html └── lecture.md ├── ex40 ├── README.me ├── index.html └── lecture.md ├── ex41 ├── README.me ├── devpkg │ ├── DEPENDS │ ├── Makefile │ ├── README │ ├── bstrlib.c │ ├── bstrlib.h │ ├── commands.c │ ├── commands.h │ ├── db.c │ ├── db.h │ ├── dbg.h │ ├── devpkg.c │ ├── shell.c │ ├── shell.h │ └── test.sh ├── ex41.1.sh ├── ex41.2.sh ├── index.html └── lecture.md ├── ex42 ├── README.me ├── index.html └── lecture.md ├── ex43 ├── README.me ├── index.html └── lecture.md ├── ex44 ├── README.me ├── index.html ├── lecture.md └── netclient.c ├── ex45 ├── README.me ├── index.html └── lecture.md ├── ex46 ├── README.me ├── index.html └── lecture.md ├── ex47 ├── README.me ├── ex47_urls.txt ├── index.html ├── lecture.md └── urlor.c ├── ex48a ├── README.me ├── index.html └── lecture.md ├── ex48b ├── README.me ├── c-skeleton │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── src │ │ ├── dbg.h │ │ └── libex29.c │ └── tests │ │ ├── libex29_tests.c │ │ ├── minunit.h │ │ └── runtests.sh ├── index.html ├── lecture.md └── statserve │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── bin │ └── statserve.c │ ├── src │ ├── dbg.h │ ├── net.c │ ├── net.h │ ├── statserve.c │ └── statserve.h │ └── tests │ ├── minunit.h │ ├── runtests.sh │ └── statserve_tests.c ├── ex49a ├── README.me ├── index.html └── lecture.md ├── ex49b ├── README.me ├── index.html ├── lecture.md └── statserve │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── bin │ └── statserve.c │ ├── src │ ├── dbg.h │ ├── net.c │ ├── net.h │ ├── statserve.c │ └── statserve.h │ └── tests │ ├── minunit.h │ ├── runtests.sh │ └── statserve_tests.c ├── ex5 ├── README.me ├── index.html └── lecture.md ├── ex50a ├── README.me ├── index.html └── lecture.md ├── ex50b ├── README.me ├── index.html ├── lecture.md └── statserve │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── bin │ └── statserve.c │ ├── src │ ├── dbg.h │ ├── net.c │ ├── net.h │ ├── statserve.c │ └── statserve.h │ └── tests │ ├── minunit.h │ ├── runtests.sh │ └── statserve_tests.c ├── ex51a ├── README.me ├── index.html └── lecture.md ├── ex51b ├── README.me ├── index.html ├── lecture.md └── statserve │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── bin │ └── statserve.c │ ├── src │ ├── dbg.h │ ├── net.c │ ├── net.h │ ├── statserve.c │ └── statserve.h │ └── tests │ ├── minunit.h │ ├── runtests.sh │ └── statserve_tests.c ├── ex52a ├── README.me ├── index.html └── lecture.md ├── ex52b ├── README.me ├── hacker.py ├── index.html └── lecture.md ├── ex52c ├── README.me ├── index.html └── lecture.md ├── ex6 ├── README.me ├── ex6.c ├── index.html └── lecture.md ├── ex7 ├── Makefile ├── README.me ├── ex7.c ├── index.html └── lecture.md ├── ex8 ├── Makefile ├── README.me ├── ex8.c ├── index.html └── lecture.md ├── ex9 ├── Makefile ├── README.me ├── ex9.c ├── index.html └── lecture.md ├── next ├── index.html └── lecture.md ├── static ├── LICENSE ├── css │ ├── print │ │ ├── paper.css │ │ └── pdf.css │ ├── reveal.css │ ├── reveal.scss │ └── theme │ │ ├── README.md │ │ ├── beige.css │ │ ├── black.css │ │ ├── blood.css │ │ ├── league.css │ │ ├── moon.css │ │ ├── night.css │ │ ├── serif.css │ │ ├── simple.css │ │ ├── sky.css │ │ ├── solarized.css │ │ ├── source │ │ ├── beige.scss │ │ ├── black.scss │ │ ├── blood.scss │ │ ├── league.scss │ │ ├── moon.scss │ │ ├── night.scss │ │ ├── serif.scss │ │ ├── simple.scss │ │ ├── sky.scss │ │ ├── solarized.scss │ │ └── white.scss │ │ ├── template │ │ ├── mixins.scss │ │ ├── settings.scss │ │ └── theme.scss │ │ └── white.css ├── js │ └── reveal.js ├── lib │ ├── css │ │ └── zenburn.css │ ├── font │ │ ├── league-gothic │ │ │ ├── LICENSE │ │ │ ├── league-gothic.css │ │ │ ├── league-gothic.eot │ │ │ ├── league-gothic.ttf │ │ │ └── league-gothic.woff │ │ └── source-sans-pro │ │ │ ├── LICENSE │ │ │ ├── source-sans-pro-italic.eot │ │ │ ├── source-sans-pro-italic.ttf │ │ │ ├── source-sans-pro-italic.woff │ │ │ ├── source-sans-pro-regular.eot │ │ │ ├── source-sans-pro-regular.ttf │ │ │ ├── source-sans-pro-regular.woff │ │ │ ├── source-sans-pro-semibold.eot │ │ │ ├── source-sans-pro-semibold.ttf │ │ │ ├── source-sans-pro-semibold.woff │ │ │ ├── source-sans-pro-semibolditalic.eot │ │ │ ├── source-sans-pro-semibolditalic.ttf │ │ │ ├── source-sans-pro-semibolditalic.woff │ │ │ └── source-sans-pro.css │ └── js │ │ ├── classList.js │ │ ├── head.min.js │ │ └── html5shiv.js └── plugin │ ├── highlight │ └── highlight.js │ ├── leap │ └── leap.js │ ├── markdown │ ├── example.html │ ├── example.md │ ├── markdown.js │ └── marked.js │ ├── math │ └── math.js │ ├── multiplex │ ├── client.js │ ├── index.js │ └── master.js │ ├── notes-server │ ├── client.js │ ├── index.js │ └── notes.html │ ├── notes │ ├── notes.html │ └── notes.js │ ├── print-pdf │ └── print-pdf.js │ ├── remotes │ └── remotes.js │ ├── search │ └── search.js │ └── zoom-js │ └── zoom.js └── template.md /.gitignore: -------------------------------------------------------------------------------- 1 | Videos 2 | .*.sw* 3 | *.pdf 4 | *.dSYM 5 | *.so 6 | *.o 7 | *.log 8 | *.db 9 | tags 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Code for the book is licensed using the MIT license: 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Zed A. Shaw 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | ======= 26 | 27 | Everything else, including lecture slides, and anything used in the videos or 28 | book are fully copyright by Zed A. Shaw and are not free to use without 29 | permission. 30 | 31 | The Reveal.js source is licensed according to their wishes. 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # basic simple Makefile starter 2 | # 3 | CFLAGS=-Wall -g 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way, Lectures 2 | ============================== 3 | 4 | This is a publicly accessible repository of code for readers of my book Learn C The Hard Way, including the lecture slides and code I create for each exercise and video. 5 | -------------------------------------------------------------------------------- /dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex0/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 0 5 | ---- 6 | 7 | Installing Software 8 | 9 | 10 | 11 | The Plan 12 | ======== 13 | 14 | * Install software on your system. 15 | * Test that it works right. 16 | 17 | 18 | 19 | Linux Install 20 | ===== 21 | 22 | On Debian/Ubuntu use: 23 | 24 | $ sudo apt-get install build-essential 25 | 26 | On RedHat/CentOS: 27 | 28 | $ sudo yum groupinstall development-tools 29 | 30 | 31 | 32 | Linux Testing 33 | ===== 34 | 35 | Test that your C compiler works with: 36 | 37 | $ cc --version 38 | 39 | 40 | 41 | OSX Install 42 | ==== 43 | 44 | Install [XCode](https://developer.apple.com/xcode/), this will take a while. 45 | 46 | 47 | 48 | OSX Testing 49 | ==== 50 | 51 | Test that your C compiler works with: 52 | 53 | $ cc --version 54 | 55 | 56 | 57 | 58 | Windows Install 59 | ==== 60 | 61 | Install [MinGW](http://www.mingw.org/) 62 | 63 | or 64 | 65 | [Cygwin](https://www.cygwin.com/) 66 | 67 | or 68 | 69 | Use [VirtualBox](https://www.virtualbox.org/wiki/Downloads) to run Linux. 70 | 71 | 72 | 73 | Text Editors 74 | ===== 75 | 76 | You should already have one. 77 | Just don't use an IDE. They aren't very helpful. 78 | 79 | 80 | 81 | End of Lecture 0 82 | ==== 83 | 84 | 85 | -------------------------------------------------------------------------------- /ex1/ex1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This is a comment. */ 4 | int main(int argc, char *argv[]) 5 | { 6 | int distance = 100; 7 | 8 | // this is also a comment 9 | printf("You are %d miles away.\n", distance); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ex1/ex1_zed.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This is a comment. */ 4 | int main(int argc, char *argv[]) 5 | { 6 | int distance = 100; 7 | 8 | // this is also a comment 9 | printf("You are %d miles away.\n"); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ex1/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 1 5 | ---- 6 | 7 | Dust Off That Compiler 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Write your first C program. 15 | * Build it. 16 | * Break it. 17 | 18 | 19 | 20 | The Code 21 | ==== 22 | 23 | https://github.com/zedshaw/learn-c-the-hard-way-lectures 24 | 25 | git clone https://github.com/zedshaw/learn-c-the-hard-way-lectures.git 26 | 27 | 28 | 29 | The Analysis 30 | ==== 31 | 32 | Let's look at it line-by-line. 33 | 34 | 35 | 36 | Breaking It 37 | ==== 38 | 39 | This is all crazy magic right now. 40 | 41 | 42 | 43 | Extra Credit 44 | ==== 45 | 46 | * Open the ``ex1`` file in your text editor and change or delete random parts. 47 | Try running it and see what happens. 48 | * Print out five more lines of text or something more complex than "hello world." 49 | * Run ``man 3 printf`` and read about this function and many others. 50 | * For each line, write out the symbols you don't understand and 51 | see if you can guess what they mean. Write a little chart on 52 | paper with your guess so you can check it later to see 53 | if you got it right. 54 | 55 | 56 | 57 | End Of Lecture 1 58 | ===== 59 | 60 | 61 | -------------------------------------------------------------------------------- /ex10/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex10/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex10/README.me -------------------------------------------------------------------------------- /ex10/ex10.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | if (argc != 2) { 6 | printf("ERROR: You need one argument.\n"); 7 | // this is how you abort a program 8 | return 1; 9 | } 10 | 11 | int i = 0; 12 | for (i = 0; argv[1][i] != '\0'; i++) { 13 | char letter = argv[1][i]; 14 | 15 | switch (letter) { 16 | case 'a': 17 | case 'A': 18 | printf("%d: 'A'\n", i); 19 | break; 20 | 21 | case 'e': 22 | case 'E': 23 | printf("%d: 'E'\n", i); 24 | break; 25 | 26 | case 'i': 27 | case 'I': 28 | printf("%d: 'I'\n", i); 29 | break; 30 | 31 | case 'o': 32 | case 'O': 33 | printf("%d: 'O'\n", i); 34 | break; 35 | 36 | case 'u': 37 | case 'U': 38 | printf("%d: 'U'\n", i); 39 | break; 40 | 41 | case 'y': 42 | case 'Y': 43 | if (i > 2) { 44 | // it's only sometimes Y 45 | printf("%d: 'Y'\n", i); 46 | } 47 | break; 48 | 49 | default: 50 | printf("%d: %c is not a vowel\n", i, letter); 51 | } 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /ex10/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 10 5 | ---- 6 | 7 | Switch Statements 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn about the *switch-statement* and indirectly jump tables. 15 | * Write a program that takes a command line argument. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | Let's talk about jump tables, in the naive sense. 28 | 29 | 30 | 31 | 32 | Breaking It 33 | ==== 34 | 35 | * Forget a *break*, and it'll run two or more blocks of code you don't want it to run. 36 | * Forget a *default*, and it'll silently ignore values you forgot. 37 | * Accidentally put a variable into the *switch* that evaluates to something unexpected, like an *int*, which becomes weird values. 38 | * Use uninitialized values in the *switch*. 39 | 40 | 41 | 42 | 43 | Extra Credit 44 | ==== 45 | 46 | * Write another program that uses math on the letter to 47 | convert it to lowercase, and then remove all of the extraneous 48 | uppercase letters in the switch. 49 | * Use the *','* (comma) to initialize *letter* 50 | in the *for-loop*. 51 | * Make it handle all of the arguments you pass it with 52 | yet another *for-loop*. 53 | 54 | 55 | 56 | Extra Credit 57 | ==== 58 | 59 | * Convert this *switch-statement* to an *if-statement*. 60 | Which do you like better? 61 | * In the case for 'Y' I have the break outside of the *if-statement*. What's the impact of this, 62 | and what happens if you move it inside of the *if-statement*. Prove to yourself that you're right. 63 | 64 | 65 | 66 | 67 | End Of Lecture 10 68 | ===== 69 | 70 | 71 | -------------------------------------------------------------------------------- /ex11/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex11/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex11/README.me -------------------------------------------------------------------------------- /ex11/ex11.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int numbers[4] = { 0 }; 6 | char name[4] = { 'a', 'a', 'a', 'a' }; 7 | 8 | // first, print them out raw 9 | printf("numbers: %d %d %d %d\n", 10 | numbers[0], numbers[1], numbers[2], numbers[3]); 11 | 12 | printf("name each: %c %c %c %c\n", 13 | name[0], name[1], name[2], name[3]); 14 | 15 | printf("name: %s\n", name); 16 | 17 | // setup the numbers 18 | numbers[0] = 1; 19 | numbers[1] = 2; 20 | numbers[2] = 3; 21 | numbers[3] = 4; 22 | 23 | // setup the name 24 | name[0] = 'Z'; 25 | name[1] = 'e'; 26 | name[2] = 'd'; 27 | name[3] = 'A'; 28 | 29 | // then print them out initialized 30 | printf("numbers: %d %d %d %d\n", 31 | numbers[0], numbers[1], numbers[2], numbers[3]); 32 | 33 | printf("name each: %c %c %c %c\n", 34 | name[0], name[1], name[2], name[3]); 35 | 36 | // print the name like a string 37 | printf("name: %s\n", name); 38 | 39 | // another way to use name 40 | char *another = "Zed"; 41 | 42 | printf("another: %s\n", another); 43 | 44 | printf("another each: %c %c %c %c\n", 45 | another[0], another[1], another[2], another[3]); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /ex11/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 11 5 | ---- 6 | 7 | Arrays and Strings 8 | 9 | 10 | 11 | 12 | The Plan 13 | ==== 14 | 15 | * Learn the similarity between arrays and strings. 16 | * Avoid getting pedantic about them. 17 | * Learn how C stores strings and processes them. 18 | 19 | 20 | The Code 21 | ==== 22 | 23 | 24 | 25 | The Analysis 26 | ==== 27 | 28 | 29 | 30 | 31 | Breaking It 32 | ==== 33 | 34 | So many ways to break this! 35 | 36 | * Get rid of the initializers that set up *name*. 37 | * Accidentally set *name[3] = 'A';* so that there's no terminator. 38 | * Set the initializer to *{'a','a','a','a'}* so that there are too many 39 | 'a' characters and no space for the *'\0'* terminator. 40 | 41 | 42 | 43 | Extra Credit 44 | ==== 45 | 46 | * Assign the characters into *numbers*, and then use *printf* 47 | to print them one character at a time. What kind of compiler warnings 48 | do you get? 49 | * Do the inverse for *name*, trying to treat it like an array 50 | of *int* and print it out one *int* at a time. What 51 | does the debugger think of that? 52 | * In how many other ways can you print this out? 53 | 54 | 55 | 56 | Extra Credit 57 | ===== 58 | 59 | * If an array of characters is 4 bytes long, and an integer is 4 bytes 60 | long, then can you treat the whole *name* array like it's just 61 | an integer? How might you accomplish this crazy hack? 62 | * Take out a piece of paper and draw each of these arrays as a 63 | row of boxes. Then do the operations you just did on paper to see 64 | if you get them right. 65 | * Convert *name* to be in the style of *another* and see 66 | if the code keeps working. 67 | 68 | 69 | 70 | End Of Lecture 11 71 | ===== 72 | 73 | 74 | -------------------------------------------------------------------------------- /ex12/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex12/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex12/README.me -------------------------------------------------------------------------------- /ex12/ex12.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int areas[] = { 10, 12, 13, 14, 20 }; 6 | char name[] = "Zed"; 7 | char full_name[] = { 8 | 'Z', 'e', 'd', 9 | ' ', 'A', '.', ' ', 10 | 'S', 'h', 'a', 'w' 11 | }; 12 | 13 | // WARNING: On some systems you may have to change the 14 | // %ld in this code to a %u since it will use unsigned ints 15 | printf("The size of an int: %ld\n", sizeof(int)); 16 | printf("The size of areas (int[]): %ld\n", sizeof(areas)); 17 | printf("The number of ints in areas: %ld\n", 18 | sizeof(areas) / sizeof(int)); 19 | printf("The first area is %d, the 2nd %d.\n", areas[0], areas[1]); 20 | 21 | printf("The size of a char: %ld\n", sizeof(char)); 22 | printf("The size of name (char[]): %ld\n", sizeof(name)); 23 | printf("The number of chars: %ld\n", sizeof(name) / sizeof(char)); 24 | 25 | printf("The size of full_name (char[]): %ld\n", sizeof(full_name)); 26 | printf("The number of chars: %ld\n", 27 | sizeof(full_name) / sizeof(char)); 28 | 29 | full_name[12] = 'X'; 30 | 31 | printf("name=\"%s\" and full_name=\"%s\"\n", name, full_name); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /ex12/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 12 5 | ---- 6 | 7 | Sizes and Arrays 8 | 9 | 10 | 11 | 12 | The Plan 13 | ==== 14 | 15 | * Learn about *sizeof* and how it relates to arrays. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | 28 | 29 | 30 | Breaking It 31 | ==== 32 | 33 | * Get rid of the *'\0'* at the end of *full_name* 34 | and re-run it. Run it under the debugger, too. Now, move the definition 35 | of *full_name* to the top of *main* before *areas*. 36 | Try running it under the debugger a few times and see if you get some 37 | new errors. In some cases, you might still get lucky and not catch 38 | any errors. 39 | * Change it so that instead of *areas[0]* you try to 40 | print *areas[10]*. See what the debugger thinks of that. 41 | * Try other ways to break it like this, doing it to *name* and 42 | *full_name* too. 43 | 44 | 45 | 46 | 47 | Extra Credit 48 | ==== 49 | 50 | * Try assigning to elements in the *areas* array with *areas[0] = 100;* and similar. 51 | * Try assigning to elements of *name* and *full_name*. 52 | * Try setting one element of *areas* to a character from *name*. 53 | * Search online for the different sizes used for integers on different 54 | CPUs. 55 | 56 | 57 | 58 | 59 | End Of Lecture 12 60 | ===== 61 | 62 | 63 | -------------------------------------------------------------------------------- /ex13/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex13/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex13/README.me -------------------------------------------------------------------------------- /ex13/ex13.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int i = 0; 6 | 7 | // go through each string in argv 8 | // why am I skipping argv[0]? 9 | for (i = 0; i < argc; i++) { 10 | printf("arg %d: %s\n", i, argv[i]); 11 | } 12 | 13 | // let's make our own array of strings 14 | char *states[] = { 15 | "California", "Oregon", 16 | "Washington", "Texas" 17 | }; 18 | 19 | int num_states = 5; 20 | 21 | for (i = 0; i < num_states; i++) { 22 | printf("state %d: %s\n", i, states[i]); 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ex13/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 13 5 | ---- 6 | 7 | For-Loops and Arrays of Strings 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Learn about this code: 15 | 16 | for(INITIALIZER; TEST; INCREMENTER) { 17 | CODE; 18 | } 19 | 20 | 21 | The Code 22 | ==== 23 | 24 | 25 | 26 | The Analysis 27 | ==== 28 | 29 | 30 | 31 | 32 | Breaking It 33 | ==== 34 | 35 | * Take your favorite other language and use it to run this program, but include as many command line arguments as possible. See if you can bust it 36 | by giving it way too many arguments. 37 | * Initialize *i* to 0 and see what that does. Do you have to adjust 38 | *argc* as well, or does it just work? Why does 0-based indexing work 39 | here? 40 | * Set *num_states* wrong so that it's a higher value and see what 41 | it does. 42 | 43 | 44 | 45 | Extra Credit 46 | ==== 47 | 48 | * Figure out what kind of code you can put into the parts of a *for-loop*. 49 | * Look up how to use the comma character (,) to separate multiple 50 | statements in the parts of the *for-loop*, but between the semicolon characters (;). 51 | * Read what a *NULL* is and try to use it in one of the elements from the 52 | *states* array to see what it'll print. 53 | * See if you can assign an element from the *states* array to the 54 | *argv* array before printing both. Try the inverse. 55 | 56 | 57 | 58 | End Of Lecture 13 59 | ===== 60 | 61 | 62 | -------------------------------------------------------------------------------- /ex14/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex14/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex14/README.me -------------------------------------------------------------------------------- /ex14/ex14.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // forward declarations 5 | int can_print_it(char ch); 6 | void print_letters(char arg[]); 7 | 8 | void print_arguments(int argc, char *argv[]) 9 | { 10 | int i = 0; 11 | 12 | for (i = 0; i < argc; i++) { 13 | print_letters(argv[i]); 14 | } 15 | } 16 | 17 | void print_letters(char arg[]) 18 | { 19 | int i = 0; 20 | 21 | for (i = 0; arg[i] != '\0'; i++) { 22 | char ch = arg[i]; 23 | 24 | if (can_print_it(ch)) { 25 | printf("'%c' == %d ", ch, ch); 26 | } 27 | } 28 | 29 | printf("\n"); 30 | } 31 | 32 | int can_print_it(char ch) 33 | { 34 | return isalpha(ch) || isblank(ch); 35 | } 36 | 37 | int main(int argc, char *argv[]) 38 | { 39 | print_arguments(argc+1, argv); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /ex14/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 14 5 | ---- 6 | 7 | Writing and Using Functions 8 | 9 | 10 | 11 | 12 | The Plan 13 | ==== 14 | 15 | * Write your very first functions. 16 | 17 | 18 | The Code 19 | ==== 20 | 21 | 22 | 23 | The Analysis 24 | ==== 25 | 26 | 27 | 28 | 29 | Breaking It 30 | ==== 31 | 32 | * Remove the forward declarations to confuse the compiler and cause it to complains about *can_print_it* and *print_letters*. 33 | * When you call *print_arguments* inside *main*, try 34 | adding 1 to *argc* so that it goes past the end of the 35 | *argv* array. 36 | 37 | 38 | 39 | Extra Credit 40 | ==== 41 | 42 | * Rework these functions so that you have fewer functions. For example, 43 | do you really need *can_print_it*? 44 | * Have *print_arguments* figure out how long each argument string 45 | is by using the *strlen* function, and then pass that length 46 | to *print_letters*. Then, rewrite *print_letters* 47 | so it only processes this fixed length and doesn't rely on the 48 | *'\0'* terminator. You'll need the *#include * for this. 49 | 50 | 51 | 52 | Extra Credit 53 | ==== 54 | 55 | * Use *man* to look up information on *isalpha* 56 | and *isblank*. Use other similar functions to 57 | print out only digits or other characters. 58 | * Go read about how other people like to format their 59 | functions. Never use the *K&R syntax* (it's antiquated and 60 | confusing) but understand what it's doing in case you run 61 | into someone who likes it. 62 | 63 | 64 | 65 | End Of Lecture 14 66 | ===== 67 | 68 | 69 | -------------------------------------------------------------------------------- /ex15/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex15/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex15/README.me -------------------------------------------------------------------------------- /ex15/ex15.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | // create two arrays we care about 6 | int ages[] = { 23, 43, 12, 89, 2 }; 7 | char *names[] = { 8 | "Alan", "Frank", 9 | "Mary", "John", "Lisa" 10 | }; 11 | 12 | // safely get the size of ages 13 | int count = sizeof(ages) / sizeof(int); 14 | int i = 0; 15 | 16 | // first way using indexing 17 | for (i = 0; i < count; i++) { 18 | printf("%s has %d years alive.\n", names[i], ages[i]); 19 | } 20 | 21 | printf("---\n"); 22 | 23 | // setup the pointers to the start of the arrays 24 | int *cur_age = (int *)names; 25 | char **cur_name = names; 26 | 27 | // second way using pointers 28 | for (i = 0; i < count; i++) { 29 | printf("%s is %d years old.\n", 30 | *(cur_name + i), *(cur_age + i)); 31 | } 32 | 33 | printf("---\n"); 34 | 35 | // third way, pointers are just arrays 36 | for (i = 0; i < count; i++) { 37 | printf("%s is %d years old again.\n", cur_name[i], cur_age[i]); 38 | } 39 | 40 | printf("---\n"); 41 | 42 | // fourth way with pointers in a stupid complex way 43 | for (cur_name = names, cur_age = ages; 44 | (cur_age - ages) < count; cur_name++, cur_age++) { 45 | printf("%s lived %d years so far.\n", *cur_name, *cur_age); 46 | } 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /ex16/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex16/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex16/README.me -------------------------------------------------------------------------------- /ex16/ex16.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct Person { 7 | char *name; 8 | int age; 9 | int height; 10 | int weight; 11 | }; 12 | 13 | struct Person *Person_create(char *name, int age, int height, 14 | int weight) 15 | { 16 | struct Person *who = malloc(sizeof(struct Person)); 17 | assert(who != NULL); 18 | 19 | who->name = strdup(name); 20 | who->age = age; 21 | who->height = height; 22 | who->weight = weight; 23 | 24 | return who; 25 | } 26 | 27 | void Person_destroy(struct Person *who) 28 | { 29 | assert(who != NULL); 30 | 31 | free(who->name); 32 | free(who); 33 | } 34 | 35 | void Person_print(struct Person *who) 36 | { 37 | printf("Name: %s\n", who->name); 38 | printf("\tAge: %d\n", who->age); 39 | printf("\tHeight: %d\n", who->height); 40 | printf("\tWeight: %d\n", who->weight); 41 | } 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | // make two people structures 46 | struct Person *joe = Person_create("Joe Alex", 32, 64, 140); 47 | 48 | struct Person *frank = Person_create("Frank Blank", 20, 72, 180); 49 | 50 | // print them out and where they are in memory 51 | printf("Joe is at memory location %p:\n", joe); 52 | Person_print(joe); 53 | 54 | printf("Frank is at memory location %p:\n", frank); 55 | Person_print(frank); 56 | 57 | // make everyone age 20 years and print them again 58 | joe->age += 20; 59 | joe->height -= 2; 60 | joe->weight += 40; 61 | Person_print(joe); 62 | 63 | frank->age += 20; 64 | frank->weight += 20; 65 | free(frank); 66 | Person_print(frank); 67 | 68 | // destroy them both so we clean up 69 | Person_destroy(joe); 70 | Person_destroy(frank); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /ex16/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 16 5 | ---- 6 | 7 | Structs And Pointers To Them 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn to work with *structs* to structure data and make new types. 15 | * Learn to use pointers to work with *structs* better. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | 28 | 29 | 30 | Breaking It 31 | ==== 32 | 33 | * Try passing *NULL* to *Person_destroy* see what 34 | it does. If it doesn't abort, then you must not have the 35 | *-g* option in your Makefile's *CFLAGS*. 36 | * Forget to call *Person_destroy* at the end, and then run 37 | it under the debugger to see it report that you forgot 38 | to free the memory. Figure out the options you need to pass 39 | to the debugger to get it to print how you leaked 40 | this memory. 41 | 42 | 43 | 44 | Breaking It 45 | ==== 46 | 47 | * Forget to free *who->name* in *Person_destroy* 48 | and compare the output. Again, use the right options to 49 | see how the debugger tells you exactly where you messed 50 | up. 51 | * This time, pass *NULL* to *Person_print* and 52 | see what the debugger thinks of that. You'll figure out that *NULL* is a quick way 53 | to crash your program. 54 | 55 | 56 | 57 | Extra Credit 58 | ==== 59 | 60 | * How to create a *struct* on the *stack* just like you're making any other variable. 61 | * How to initialize it using the *x.y* (period) character 62 | instead of the *x->y* syntax. 63 | * How to pass a structure to other functions without using 64 | a pointer. 65 | 66 | 67 | 68 | End Of Lecture 16 69 | ===== 70 | 71 | 72 | -------------------------------------------------------------------------------- /ex17/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex17/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex17/README.me -------------------------------------------------------------------------------- /ex18/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex18/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex18/README.me -------------------------------------------------------------------------------- /ex18/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 18 5 | ---- 6 | 7 | Pointers to Functions 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Advanced topic of pointers to functions. 15 | * These are very useful but not encountered too often. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | 28 | 29 | 30 | Breaking It 31 | ==== 32 | 33 | Let's hack your computer with this code: 34 | 35 | unsigned char *data = (unsigned char *)cmp; 36 | 37 | for(i = 0; i < 25; i++) { 38 | printf("%02x:", data[i]); 39 | } 40 | 41 | printf("\n"); 42 | 43 | You'll see how the bytes of code that make up your program can also be data. 44 | 45 | 46 | Extra Credit 47 | ==== 48 | 49 | * Get a hex editor and open up *ex18*, and then find the sequence 50 | of hex digits that start a function to see if you can find the function 51 | in the raw program. 52 | * Find other random things in your hex editor and change them. Rerun your 53 | program and see what happens. Strings you find are the easiest 54 | things to change. 55 | * Pass in the wrong function for the *compare_cb* and see what 56 | the C compiler complains about. 57 | * Pass in NULL and watch your program seriously bite it. Then, run 58 | the debugger and see what that reports. 59 | * Write another sorting algorithm, then change *test_sorting* so 60 | that it takes *both* an arbitrary sort function and the sort function's 61 | callback comparison. Use it to test both of your algorithms. 62 | 63 | 64 | 65 | End Of Lecture 18 66 | ===== 67 | 68 | 69 | -------------------------------------------------------------------------------- /ex19/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex19/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex19/README.me -------------------------------------------------------------------------------- /ex19/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex19/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 19 5 | ---- 6 | 7 | Zed's Awesome Debug Macros 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn about the macros that vastly improve my code quality. 15 | * Find out why they help you out. 16 | * Explore some advanced C Pre-Processor (CPP) macro magic code generation tricks. 17 | 18 | 19 | 20 | The Code 21 | ==== 22 | 23 | 24 | 25 | The Analysis 26 | ==== 27 | 28 | 29 | 30 | Breaking It 31 | ==== 32 | 33 | These macros are designed on purpose to prevent you from doing this: 34 | 35 | if(blah) debug("This is a thing"); 36 | else debug ("This is another thing"); 37 | 38 | 39 | 40 | Extra Credit 41 | ==== 42 | 43 | * Put ``#define NDEBUG`` at the top of the file and check that all 44 | of the debug messages go away. 45 | * Undo that line, and add ``-DNDEBUG`` to ``CFLAGS`` at the 46 | top of the ``Makefile``, and then recompile to see the same thing. 47 | * Modify the logging so that it includes the function name, as well 48 | as the ``file:line``. 49 | 50 | 51 | 52 | End Of Lecture 19 53 | ===== 54 | 55 | 56 | -------------------------------------------------------------------------------- /ex2/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: ex1 4 | 5 | clean: 6 | rm -f ex1 7 | 8 | -------------------------------------------------------------------------------- /ex2/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex2/README.me -------------------------------------------------------------------------------- /ex2/ex1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This is a comment. */ 4 | int main(int argc, char *argv[]) 5 | { 6 | int distance = 100; 7 | 8 | // this is also a comment 9 | printf("You are %d miles away.\n", distance); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ex2/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 2 5 | ---- 6 | 7 | Using Makefiles to Build 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Start with simple make usage. 15 | * Set a few important settings. 16 | 17 | 18 | 19 | How Make Works 20 | ==== 21 | 22 | Implied dependencies and ancient lore. 23 | 24 | 25 | 26 | Shell Commands 27 | ==== 28 | 29 | $ make ex1 30 | # or this one too 31 | $ CFLAGS="-Wall" make ex1 32 | $ make clean 33 | $ make ex1 34 | 35 | 36 | 37 | Makefile 38 | ==== 39 | 40 | CFLAGS=-Wall -g 41 | 42 | clean: 43 | rm -f ex1 44 | 45 | 46 | 47 | The Analysis 48 | ==== 49 | 50 | * Setting options. 51 | * Indicating dependencies. 52 | * Writing commends to run. 53 | 54 | 55 | Breaking It 56 | ==== 57 | 58 | * Watch out for tabs vs. spaces. 59 | 60 | 61 | 62 | 63 | Extra Credit 64 | ==== 65 | 66 | * Create an *all: ex1* target that will build *ex1* with 67 | just the command *make*. 68 | * Read *man make* to find out more information on how to run it. 69 | * Read *man cc* to find out more information on what the flags *-Wall* and *-g* do. 70 | * Research *Makefiles* online and see if you can improve this one. 71 | * Find a *Makefile* in another C project and try to understand 72 | what it's doing. 73 | 74 | 75 | 76 | End Of Lecture 2 77 | ===== 78 | 79 | 80 | -------------------------------------------------------------------------------- /ex20/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex20/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex20/README.me -------------------------------------------------------------------------------- /ex20/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex20/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 20 5 | ---- 6 | 7 | Advanced Debugging Techniques 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Demonstrate more advanced debugging techniques and tools. 15 | 16 | 17 | The Demonstration 18 | ==== 19 | 20 | 21 | 22 | 23 | Extra Credit 24 | ==== 25 | 26 | * Find a graphical debugger and compare using it to raw ``gdb``. 27 | These are useful when the program you're looking at is local, but they 28 | are pointless if you have to debug a program on a server. 29 | * You can enable core dumps on your OS, and when a program crashes, 30 | you'll get a core file. This core file is like a postmortem of 31 | the program that you can load up to see what happened right at the crash 32 | and what caused it. Change ``ex31.c`` so that it crashes 33 | after a few iterations, then try to get a core dump and analyze it. 34 | 35 | 36 | 37 | End Of Lecture 20 38 | ===== 39 | 40 | 41 | -------------------------------------------------------------------------------- /ex20/test.sh: -------------------------------------------------------------------------------- 1 | rm ex20 2 | make ex20 3 | ./ex20 1 82 39 44 1 2 3 4 9 8 01 10 11 4 | -------------------------------------------------------------------------------- /ex21/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: 4 | cc $(CFLAGS) -o ex21 ex21.c ex21_main.c 5 | -------------------------------------------------------------------------------- /ex21/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex21/README.me -------------------------------------------------------------------------------- /ex22/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex22/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex22/README.me -------------------------------------------------------------------------------- /ex22/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex22/ex22.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ex22.h" 3 | #include "dbg.h" 4 | 5 | int get_age(struct State *state) 6 | { 7 | return state->the_age; 8 | } 9 | 10 | void set_age(struct State *state, int age) 11 | { 12 | state->the_age = age; 13 | } 14 | 15 | double update_ratio(double new_ratio) 16 | { 17 | static double ratio = 1.0; 18 | 19 | double old_ratio = ratio; 20 | ratio = new_ratio; 21 | 22 | return old_ratio; 23 | } 24 | 25 | void print_size() 26 | { 27 | log_info("I think size is: %d", THE_SIZE); 28 | } 29 | -------------------------------------------------------------------------------- /ex22/ex22.h: -------------------------------------------------------------------------------- 1 | #ifndef _ex22_h 2 | #define _ex22_h 3 | 4 | struct State { 5 | int the_size; 6 | int the_age; 7 | }; 8 | 9 | 10 | // gets and sets an internal static variable in ex22.c 11 | int get_age(struct State *state); 12 | void set_age(struct State *state, int age); 13 | 14 | // updates a static variable that's inside update_ratio 15 | double update_ratio(double ratio); 16 | 17 | void print_size(); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ex22/ex22_main.c: -------------------------------------------------------------------------------- 1 | #include "ex22.h" 2 | #include "dbg.h" 3 | 4 | const char *MY_NAME = "Zed A. Shaw"; 5 | 6 | void scope_demo(int count) 7 | { 8 | log_info("count is: %d", count); 9 | 10 | if (count > 10) { 11 | int numbers = 100; // BAD! BUGS! 12 | 13 | log_info("count in this scope is %d", numbers); 14 | } 15 | 16 | log_info("count is at exit: %d", count); 17 | 18 | count = 3000; 19 | 20 | log_info("count after assign: %d", count); 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | // test out THE_AGE accessors 26 | log_info("My name: %s, age: %d", MY_NAME, get_age()); 27 | 28 | set_age(100); 29 | 30 | log_info("My age is now: %d", get_age()); 31 | 32 | // test out THE_SIZE extern 33 | log_info("THE_SIZE is: %d", THE_SIZE); 34 | print_size(); 35 | 36 | THE_SIZE = 9; 37 | 38 | log_info("THE SIZE is now: %d", THE_SIZE); 39 | print_size(); 40 | 41 | // test the ratio function static 42 | log_info("Ratio at first: %f", update_ratio(2.0)); 43 | log_info("Ratio again: %f", update_ratio(10.0)); 44 | log_info("Ratio once more: %f", update_ratio(300.0)); 45 | 46 | // test the scope demo 47 | int count = 4; 48 | scope_demo(count); 49 | scope_demo(count * 20); 50 | 51 | log_info("count after calling scope_demo: %d", count); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /ex22/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 22 5 | ---- 6 | 7 | The Stack, Scope, and Globals 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Start to learn about scope. 15 | * Stack vs. global. 16 | * Scope levels inside a function. 17 | * The *extern* keyword. 18 | 19 | 20 | The Code 21 | ==== 22 | 23 | This exercises requires two files: 24 | 25 | * ex22.c 26 | * ex22_main.c 27 | 28 | 29 | 30 | The Analysis 31 | ==== 32 | 33 | 34 | 35 | Fixing It 36 | ==== 37 | 38 | Instead of breaking this one I'm going to fix it. 39 | 40 | * Do not shadow a variable like *count* on ex22_main.c:11. 41 | * Avoid using too many globals. 42 | * When in doubt, put it on the heap (malloc). 43 | * Don't use function static variables like I did in ex22.c:update_ratio. 44 | * Avoid reusing function parameters. 45 | 46 | 47 | 48 | Breaking It 49 | ==== 50 | 51 | * Try to directly access variables in ``ex22.c`` from ``ex22_main.c`` 52 | that you think you can't. For example, can you get at ``ratio`` 53 | inside ``update_ratio``? What if you had a pointer to it? 54 | * Ditch the ``extern`` declaration in ``ex22.h`` to see what 55 | errors or warnings you get. 56 | * Add ``static`` or ``const`` specifiers to different variables, 57 | and then try to change them. 58 | 59 | 60 | 61 | Extra Credit 62 | ==== 63 | 64 | * Research the concept of pass by value verses pass by reference. Write an 65 | example of both. 66 | * Use pointers to gain access to things you shouldn't have access to. 67 | * Use your debugger to see what this kind of access looks like when you 68 | do it wrong. 69 | * Write a recursive function that causes a stack overflow. Don't know 70 | what a recursive function is? Try calling ``scope_demo`` at the 71 | bottom of ``scope_demo`` itself so that it loops. 72 | * Rewrite the ``Makefile`` so that it can build this. 73 | 74 | 75 | 76 | End Of Lecture 22 77 | ===== 78 | 79 | 80 | -------------------------------------------------------------------------------- /ex23/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex23/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex23/README.me -------------------------------------------------------------------------------- /ex23/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex24/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex24/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex24/README.me -------------------------------------------------------------------------------- /ex24/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex24/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 24 5 | ---- 6 | 7 | Input, Output, Files 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn the basics of working with files in C. 15 | * Get an initial list of the "f-functions". 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | 28 | 29 | Breaking It 30 | ==== 31 | 32 | * Trying out *fgets* and the problems with *gets*. 33 | * Feed it */dev/urandom* to give it garbage. 34 | 35 | 36 | 37 | Extra Credit 38 | ==== 39 | 40 | * Rewrite this to not use ``fscanf`` at all. You'll need to use 41 | functions like ``atoi`` to convert the input strings to numbers. 42 | * Change this to use plain ``scanf`` instead of ``fscanf`` to 43 | see what the difference is. 44 | * Fix it so that their input names get stripped of the trailing newline 45 | characters and any whites pace. 46 | 47 | 48 | 49 | Extra Credit 50 | ==== 51 | 52 | * Use ``scanf`` to write a function that reads one character at a time 53 | and files in the names but doesn't go past the end. Make this function 54 | generic so it can take a size for the string, but just make sure you end 55 | the string with ``'\0'`` no matter what. 56 | 57 | 58 | 59 | End Of Lecture 24 60 | ===== 61 | 62 | 63 | -------------------------------------------------------------------------------- /ex25/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex25/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex25/README.me -------------------------------------------------------------------------------- /ex25/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex25/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 25 5 | ---- 6 | 7 | Variable Argument Functions 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Use variable argument functions. 15 | * Write our own simple version of *scanf*. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | 28 | 29 | Breaking It 30 | ==== 31 | 32 | * Change the code so that you forget to pass in the initial size for '%s' formats. 33 | * Give it more data than ``MAX_DATA``, and then see how omitting ``calloc`` in ``read_string`` changes how it works. 34 | * There's a problem where fgets eats the newlines, so try to fix that using 35 | ``fgetc`` but leave out the ``\0`` that ends the string. 36 | 37 | 38 | 39 | Extra Credit 40 | ==== 41 | 42 | * Make double and triple sure that you know what each of the ``out_`` 43 | variables are doing. Most importantly, you should know what is ``out_string`` is and how it's 44 | a pointer to a pointer, , so that you understand when you're setting the pointer versus the 45 | contents is important. Break down each of the 46 | 47 | 48 | 49 | Extra Credit 50 | ==== 51 | 52 | * Write a similar function to ``printf`` that uses the varargs system, 53 | and rewrite ``main`` to use it. 54 | * As usual, read the man page on all of this so that you know what it does 55 | on your platform. Some platforms will use macros, others will use 56 | functions, and some will have these do nothing. It all depends on the 57 | compiler and the platform you use. 58 | 59 | 60 | 61 | End Of Lecture 25 62 | ===== 63 | 64 | -------------------------------------------------------------------------------- /ex26/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex26/README.me -------------------------------------------------------------------------------- /ex26/logfind.1/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: logfind 4 | ./logfind || true 5 | ./logfind test test test 6 | 7 | -------------------------------------------------------------------------------- /ex26/logfind.1/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex26/logfind.1/logfind.c: -------------------------------------------------------------------------------- 1 | #include "dbg.h" 2 | 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | check(argc > 2, "USAGE: logfind word word word"); 7 | 8 | return 0; 9 | 10 | error: 11 | return 1; 12 | } 13 | -------------------------------------------------------------------------------- /ex26/logfind.2/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: logfind 4 | ./logfind || true 5 | ./logfind error 6 | 7 | clean: 8 | rm -f logfind 9 | -------------------------------------------------------------------------------- /ex26/logfind.2/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex26/logfind.2/logfind.c: -------------------------------------------------------------------------------- 1 | #include "dbg.h" 2 | #include 3 | #include 4 | #include 5 | 6 | const size_t MAX_LINE = 1024; 7 | 8 | int scan_file(const char *filename, int search_len, char *search_for[]) 9 | { 10 | char *line = calloc(MAX_LINE, 1); 11 | FILE *file = fopen(filename, "r"); 12 | char *found = NULL; 13 | int i = 0; 14 | 15 | check_mem(line); 16 | check(file, "Failed to open file: %s", filename); 17 | 18 | // read each line of the file and search that line for the contents 19 | while(fgets(line, MAX_LINE-1, file) != NULL && found == NULL) { 20 | for(i = 0; i < search_len && found == NULL; i++) { 21 | found = strcasestr(line, search_for[i]); 22 | if(found) { 23 | printf("%s\n", filename); 24 | } 25 | } 26 | } 27 | 28 | free(line); 29 | fclose(file); 30 | return 0; 31 | 32 | error: 33 | if(line) free(line); 34 | if(file) fclose(file); 35 | 36 | return -1; 37 | } 38 | 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | check(argc > 1, "USAGE: logfind word word word"); 43 | 44 | scan_file("logfind.c", argc, argv); 45 | 46 | return 0; 47 | 48 | error: 49 | return 1; 50 | } 51 | -------------------------------------------------------------------------------- /ex26/logfind.3/.logfind: -------------------------------------------------------------------------------- 1 | *.c 2 | *.h 3 | Makefile 4 | -------------------------------------------------------------------------------- /ex26/logfind.3/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: logfind 4 | ./logfind || true 5 | ./logfind error 6 | 7 | clean: 8 | rm -f logfind 9 | -------------------------------------------------------------------------------- /ex26/logfind.3/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex26/logfind.4/.logfind: -------------------------------------------------------------------------------- 1 | *.c 2 | *.h 3 | Makefile 4 | -------------------------------------------------------------------------------- /ex26/logfind.4/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: logfind 4 | ./logfind || true 5 | ./logfind MAX_LINE 6 | 7 | clean: 8 | rm -f logfind 9 | -------------------------------------------------------------------------------- /ex26/logfind.4/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex26/logfind.5/.logfind: -------------------------------------------------------------------------------- 1 | *.c 2 | *.h 3 | Makefile 4 | -------------------------------------------------------------------------------- /ex26/logfind.5/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: logfind 4 | ./logfind || true 5 | ./logfind MAX_LINE 6 | ./logfind error MAX LINE 7 | ./logfind -o error MAX LINE 8 | 9 | clean: 10 | rm -f logfind 11 | -------------------------------------------------------------------------------- /ex26/logfind.5/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex27/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex27/README.me -------------------------------------------------------------------------------- /ex27/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 27 5 | ---- 6 | 7 | Creative and Defensive Programming 8 | 9 | 10 | 11 | Read The Book 12 | ==== 13 | 14 | This video is a demonstration of the concepts in the book. 15 | 16 | Go read the book. 17 | 18 | 19 | 20 | Demonstration 21 | ==== 22 | 23 | I will demonstrate each of the following: 24 | 25 | * Fail early and openly. 26 | * Document assumptions. 27 | * Prevention over documentation. 28 | * Automate everything. 29 | * Simplify and clarify. 30 | * Question authority. 31 | 32 | 33 | 34 | Fail Early and Openly 35 | ==== 36 | 37 | 38 | 39 | Document Assumptions 40 | ==== 41 | 42 | 43 | 44 | Prevention over Documentation 45 | ==== 46 | 47 | 48 | 49 | Automate Everything 50 | ==== 51 | 52 | 53 | 54 | Simplify and Clarify 55 | ==== 56 | 57 | 58 | 59 | Question Authority 60 | ==== 61 | 62 | 63 | 64 | Bonus: Assume Nothing 65 | ==== 66 | 67 | 68 | 69 | End Of Lecture 27 70 | ===== 71 | 72 | 73 | -------------------------------------------------------------------------------- /ex27/logfind.5/.logfind: -------------------------------------------------------------------------------- 1 | *.c 2 | *.h 3 | Makefile 4 | -------------------------------------------------------------------------------- /ex27/logfind.5/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | all: logfind 4 | ./logfind || true 5 | ./logfind MAX_LINE 6 | ./logfind error MAX LINE 7 | ./logfind -o error MAX LINE 8 | 9 | clean: 10 | rm -f logfind 11 | -------------------------------------------------------------------------------- /ex27/logfind.5/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex28/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex28/README.me -------------------------------------------------------------------------------- /ex28/c-skeleton/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex28/c-skeleton/LICENSE -------------------------------------------------------------------------------- /ex28/c-skeleton/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS) 2 | LIBS=-ldl $(OPTLIBS) 3 | PREFIX?=/usr/local 4 | 5 | SOURCES=$(wildcard src/**/*.c src/*.c) 6 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 7 | 8 | TEST_SRC=$(wildcard tests/*_tests.c) 9 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 10 | 11 | TARGET=build/libYOUR_LIBRARY.a 12 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 13 | 14 | # The Target Build 15 | all: $(TARGET) $(SO_TARGET) tests 16 | 17 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 18 | dev: all 19 | 20 | $(TARGET): CFLAGS += -fPIC 21 | $(TARGET): build $(OBJECTS) 22 | ar rcs $@ $(OBJECTS) 23 | ranlib $@ 24 | 25 | $(SO_TARGET): $(TARGET) $(OBJECTS) 26 | $(CC) -shared -o $@ $(OBJECTS) 27 | 28 | build: 29 | @mkdir -p build 30 | @mkdir -p bin 31 | 32 | # The Unit Tests 33 | .PHONY: tests 34 | tests: CFLAGS += $(TARGET) 35 | tests: $(TESTS) 36 | sh ./tests/runtests.sh 37 | 38 | # The Cleaner 39 | clean: 40 | rm -rf build $(OBJECTS) $(TESTS) 41 | rm -f tests/tests.log 42 | find . -name "*.gc*" -exec rm {} \; 43 | rm -rf `find . -name "*.dSYM" -print` 44 | 45 | # The Install 46 | install: all 47 | install -d $(DESTDIR)/$(PREFIX)/lib/ 48 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 49 | 50 | # The Checker 51 | check: 52 | @echo Files with potentially dangerous functions. 53 | @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ 54 | |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true 55 | 56 | -------------------------------------------------------------------------------- /ex28/c-skeleton/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex28/c-skeleton/README.md -------------------------------------------------------------------------------- /ex28/c-skeleton/src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex28/c-skeleton/src/libex29.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dbg.h" 4 | 5 | 6 | int print_a_message(const char *msg) 7 | { 8 | printf("A STRING: %s\n", msg); 9 | 10 | return 0; 11 | } 12 | 13 | 14 | int uppercase(const char *msg) 15 | { 16 | int i = 0; 17 | 18 | // BUG: \0 termination problems 19 | for(i = 0; msg[i] != '\0'; i++) { 20 | printf("%c", toupper(msg[i])); 21 | } 22 | 23 | printf("\n"); 24 | 25 | return 0; 26 | } 27 | 28 | int lowercase(const char *msg) 29 | { 30 | int i = 0; 31 | 32 | // BUG: \0 termination problems 33 | for(i = 0; msg[i] != '\0'; i++) { 34 | printf("%c", tolower(msg[i])); 35 | } 36 | 37 | printf("\n"); 38 | 39 | return 0; 40 | } 41 | 42 | int fail_on_purpose(const char *msg) 43 | { 44 | return 1; 45 | } 46 | -------------------------------------------------------------------------------- /ex28/c-skeleton/tests/libex29_tests.c: -------------------------------------------------------------------------------- 1 | #include "minunit.h" 2 | #include 3 | 4 | typedef int (*lib_function) (const char *data); 5 | char *lib_file = "build/libYOUR_LIBRARY.so"; 6 | void *lib = NULL; 7 | 8 | int check_function(const char *func_to_run, const char *data, 9 | int expected) 10 | { 11 | lib_function func = dlsym(lib, func_to_run); 12 | check(func != NULL, 13 | "Did not find %s function in the library %s: %s", func_to_run, 14 | lib_file, dlerror()); 15 | 16 | int rc = func(data); 17 | check(rc == expected, "Function %s return %d for data: %s", 18 | func_to_run, rc, data); 19 | 20 | return 1; 21 | error: 22 | return 0; 23 | } 24 | 25 | char *test_dlopen() 26 | { 27 | lib = dlopen(lib_file, RTLD_NOW); 28 | mu_assert(lib != NULL, "Failed to open the library to test."); 29 | 30 | return NULL; 31 | } 32 | 33 | char *test_functions() 34 | { 35 | mu_assert(check_function("print_a_message", "Hello", 0), 36 | "print_a_message failed."); 37 | mu_assert(check_function("uppercase", "Hello", 0), 38 | "uppercase failed."); 39 | mu_assert(check_function("lowercase", "Hello", 0), 40 | "lowercase failed."); 41 | 42 | return NULL; 43 | } 44 | 45 | char *test_failures() 46 | { 47 | mu_assert(check_function("fail_on_purpose", "Hello", 1), 48 | "fail_on_purpose should fail."); 49 | 50 | return NULL; 51 | } 52 | 53 | char *test_dlclose() 54 | { 55 | int rc = dlclose(lib); 56 | mu_assert(rc == 0, "Failed to close lib."); 57 | 58 | return NULL; 59 | } 60 | 61 | char *all_tests() 62 | { 63 | mu_suite_start(); 64 | 65 | mu_run_test(test_dlopen); 66 | mu_run_test(test_functions); 67 | mu_run_test(test_failures); 68 | mu_run_test(test_dlclose); 69 | 70 | return NULL; 71 | } 72 | 73 | RUN_TESTS(all_tests); 74 | -------------------------------------------------------------------------------- /ex28/c-skeleton/tests/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) {\ 12 | log_err(message); return message; } 13 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 14 | message = test(); tests_run++; if (message) return message; 15 | 16 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 17 | argc = 1; \ 18 | debug("----- RUNNING: %s", argv[0]);\ 19 | printf("----\nRUNNING: %s\n", argv[0]);\ 20 | char *result = name();\ 21 | if (result != 0) {\ 22 | printf("FAILED: %s\n", result);\ 23 | }\ 24 | else {\ 25 | printf("ALL TESTS PASSED\n");\ 26 | }\ 27 | printf("Tests run: %d\n", tests_run);\ 28 | exit(result != 0);\ 29 | } 30 | 31 | int tests_run; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex28/c-skeleton/tests/runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in tests/*_tests 4 | do 5 | if test -f $i 6 | then 7 | if $VALGRIND ./$i 2>> tests/tests.log 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i: here's tests/tests.log" 12 | echo "------" 13 | tail tests/tests.log 14 | exit 1 15 | fi 16 | fi 17 | done 18 | 19 | echo "" 20 | -------------------------------------------------------------------------------- /ex28/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 28 5 | ---- 6 | 7 | Intermediate Makefiles 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn how to create a project skeleton to make starting easier. 15 | * Learn more advanced GNU make tricks. 16 | 17 | 18 | 19 | The Skeleton 20 | ==== 21 | 22 | The video is probably easier to follow than the book. 23 | Watch me do this. 24 | 25 | 26 | 27 | Using The Skeleton 28 | ==== 29 | 30 | Now I'll use the skeleton to start a simple project for the next exercise. 31 | 32 | 33 | 34 | The Analysis 35 | ==== 36 | 37 | Let's look at Makefile in depth. 38 | 39 | 40 | 41 | Extra Credit 42 | ==== 43 | 44 | 45 | 46 | End Of Lecture 28 47 | ===== 48 | 49 | 50 | -------------------------------------------------------------------------------- /ex29/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex29/README.me -------------------------------------------------------------------------------- /ex29/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex29/ex29.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dbg.h" 3 | #include 4 | 5 | typedef int (*lib_function) (const char *data); 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | int rc = 0; 10 | check(argc == 4, "USAGE: ex29 libex29.so function data"); 11 | 12 | char *lib_file = argv[1]; 13 | char *func_to_run = argv[2]; 14 | char *data = argv[3]; 15 | 16 | void *lib = dlopen(lib_file, RTLD_NOW); 17 | check(lib != NULL, "Failed to open the library %s: %s", lib_file, 18 | dlerror()); 19 | 20 | lib_function func = dlsym(lib, func_to_run); 21 | check(func != NULL, 22 | "Did not find %s function in the library %s: %s", func_to_run, 23 | lib_file, dlerror()); 24 | 25 | rc = func(data); 26 | check(rc == 0, "Function %s return %d for data: %s", func_to_run, 27 | rc, data); 28 | 29 | rc = dlclose(lib); 30 | check(rc == 0, "Failed to close %s", lib_file); 31 | 32 | return 0; 33 | 34 | error: 35 | return 1; 36 | } 37 | -------------------------------------------------------------------------------- /ex29/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 29 5 | ---- 6 | 7 | Libraries and Linking 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn about libraries and how to link against them. 15 | * Learn how to load a dynamic library from inside C. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | I'll use the project I started from the previous exercise. 23 | This covers some of the extra credit. 24 | 25 | 26 | 27 | The Analysis 28 | ==== 29 | 30 | This analysis might take a while, but be sure you know Exercise 28 well. 31 | 32 | 33 | 34 | Breaking It 35 | ==== 36 | 37 | * Wreck the libex29.so file. 38 | 39 | 40 | 41 | Extra Credit 42 | ==== 43 | 44 | * Were you paying attention to the bad code I have in the ``libex29.c`` functions? 45 | Do you see how, even though I use a for-loop they still check for ``'\0'`` 46 | endings? Fix this so that the functions always take a length for the 47 | string to work with inside the function. 48 | * Read the ``man dlopen`` documentation and read about all of the 49 | related functions. Try some of the other options to ``dlopen`` 50 | beside ``RTLD_NOW``. 51 | 52 | 53 | 54 | 55 | End Of Lecture 29 56 | ===== 57 | 58 | 59 | -------------------------------------------------------------------------------- /ex29/libex29.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dbg.h" 4 | 5 | 6 | int print_a_message(const char *msg) 7 | { 8 | printf("A STRING: %s\n", msg); 9 | 10 | return 0; 11 | } 12 | 13 | 14 | int uppercase(const char *msg) 15 | { 16 | int i = 0; 17 | 18 | // BUG: \0 termination problems 19 | for(i = 0; msg[i] != '\0'; i++) { 20 | printf("%c", toupper(msg[i])); 21 | } 22 | 23 | printf("\n"); 24 | 25 | return 0; 26 | } 27 | 28 | int lowercase(const char *msg) 29 | { 30 | int i = 0; 31 | 32 | // BUG: \0 termination problems 33 | for(i = 0; msg[i] != '\0'; i++) { 34 | printf("%c", tolower(msg[i])); 35 | } 36 | 37 | printf("\n"); 38 | 39 | return 0; 40 | } 41 | 42 | int fail_on_purpose(const char *msg) 43 | { 44 | return 1; 45 | } 46 | -------------------------------------------------------------------------------- /ex3/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | clean: 4 | rm -f ex3 5 | 6 | -------------------------------------------------------------------------------- /ex3/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex3/README.me -------------------------------------------------------------------------------- /ex3/ex3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int age = 100; 6 | int height = 72; 7 | 8 | printf("I am %d years old.\n", argv); 9 | printf("I am %d inches tall.\n", height); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ex3/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 3 5 | ---------- 6 | 7 | Formatted Printing 8 | 9 | 10 | 11 | 12 | The Plan 13 | ==== 14 | 15 | * Introduction to *printf*. 16 | 17 | 18 | The Code 19 | ==== 20 | 21 | 22 | 23 | The Analysis 24 | ==== 25 | 26 | 27 | 28 | Breaking It 29 | ==== 30 | 31 | * Take the *age* variable out of the first *printf* call, then recompile. You should get a couple of warnings. 32 | * Run this new program and it will either crash or print out a really crazy age. 33 | * Put the *printf* back the way it was, and then don't set *age* to an initial value by changing that line to *int age;*, and then rebuild it and run it again. 34 | 35 | 36 | 37 | 38 | Extra Credit 39 | ==== 40 | 41 | * Find as many other ways to break *ex3.c* as you can. 42 | * Run *man 3 printf* and read about the other *%* format 43 | characters you can use. These should look familiar if you used 44 | them in other languages (they come from *printf*). 45 | * Add *ex3* the *all* list in your *Makefile*. Use this 46 | to *make clean all* and build all of your exercises thus far. 47 | * Add *ex3* to your *clean* list in your*Makefile* as well. 48 | Use *make clean* to remove it when you need to. 49 | 50 | 51 | 52 | End Of Lecture 3 53 | ===== 54 | 55 | 56 | -------------------------------------------------------------------------------- /ex30/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex30/README.me -------------------------------------------------------------------------------- /ex30/ex30.c: -------------------------------------------------------------------------------- 1 | #include "minunit.h" 2 | 3 | char *test_dlopen(int stuff) 4 | { 5 | return NULL; 6 | } 7 | 8 | char *test_functions() 9 | { 10 | 11 | return NULL; 12 | } 13 | 14 | char *test_failures() 15 | { 16 | 17 | return NULL; 18 | } 19 | 20 | char *test_dlclose() 21 | { 22 | 23 | return NULL; 24 | } 25 | 26 | char *all_tests() 27 | { 28 | mu_suite_start(); 29 | 30 | mu_run_test(test_dlopen); 31 | mu_run_test(test_functions); 32 | mu_run_test(test_failures); 33 | mu_run_test(test_dlclose); 34 | 35 | return NULL; 36 | } 37 | 38 | RUN_TESTS(all_tests); 39 | -------------------------------------------------------------------------------- /ex30/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 30 5 | ---- 6 | 7 | Automated Testing 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Continue the Exercise 28-29 project and add automated tests to it. 15 | 16 | 17 | 18 | Why Automate Tests 19 | ==== 20 | 21 | You are a programmer. 22 | Your job is automating. 23 | 24 | EVERYTHING 25 | ---- 26 | 27 | 28 | 29 | The Code 30 | ==== 31 | 32 | 33 | 34 | Adding It To libex29 35 | ==== 36 | 37 | 38 | 39 | Breaking It 40 | ==== 41 | 42 | * Making tests fail first is useful. 43 | 44 | 45 | 46 | Extra Credit 47 | ==== 48 | 49 | * This works but it's probably a bit messy. Clean the ``c-skeleton`` 50 | directory up so that it has all of these files, but remove any of the code 51 | related to Exercise 29. You should be able to copy this directory 52 | over and kick-start new projects without much editing. 53 | * Study the ``runtests.sh``, and then go read about ``bash`` syntax 54 | so you know what it does. Do you think you could write a C version of this 55 | script? 56 | 57 | 58 | 59 | End Of Lecture 30 60 | ===== 61 | 62 | 63 | -------------------------------------------------------------------------------- /ex31/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex31/README.me -------------------------------------------------------------------------------- /ex31/ex31.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int i = 0; 6 | 7 | while (i < 100) { 8 | usleep(3000); 9 | } 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ex31/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 31 5 | ---- 6 | 7 | Common Undefined Behavior 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Review the issues around Undefined and Unspecified Behavior (UB). 15 | 16 | 17 | 18 | Read The Book 19 | ==== 20 | 21 | The book lists many of the UB and discusses why they are important to know 22 | about. 23 | 24 | 25 | 26 | The Code 27 | ==== 28 | 29 | There is no code for this exercise, just a quick discussion for the book. 30 | 31 | 32 | 33 | Undefined Behavior 34 | ==== 35 | 36 | * Compiler writers can do whatever they want. 37 | * This means even *nothing*, which will ruin you silently. 38 | * It's best to avoid it. 39 | 40 | 41 | 42 | Unspecified Behavior 43 | ==== 44 | 45 | * For practical purposes unspecified is the same as undefined. 46 | 47 | 48 | 49 | Handy Tools 50 | ==== 51 | 52 | * Clang's UB helpful flags. 53 | * Lint tools and static analyzers. 54 | 55 | 56 | 57 | Extra Credit 58 | ==== 59 | 60 | Spend a day reading through as much of the UB as you can and find examples of each. Expect lots of frustration and failure when you do this. 61 | 62 | 63 | 64 | End Of Lecture 31 65 | ===== 66 | 67 | 68 | -------------------------------------------------------------------------------- /ex32/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex32/README.me -------------------------------------------------------------------------------- /ex33/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex33/README.me -------------------------------------------------------------------------------- /ex34/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex34/README.me -------------------------------------------------------------------------------- /ex35/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex35/README.me -------------------------------------------------------------------------------- /ex35/ex35.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef enum { 4 | TYPE_INT, 5 | TYPE_FLOAT, 6 | TYPE_STRING, 7 | } VariantType; 8 | 9 | struct Variant { 10 | VariantType type; 11 | union { 12 | int as_integer; 13 | float as_float; 14 | char *as_string; 15 | } data; 16 | }; 17 | 18 | typedef struct Variant Variant; 19 | 20 | void Variant_print(Variant * var) 21 | { 22 | switch (var->type) { 23 | case TYPE_INT: 24 | printf("INT: %d\n", var->data.as_integer); 25 | break; 26 | case TYPE_FLOAT: 27 | printf("FLOAT: %f\n", var->data.as_float); 28 | break; 29 | case TYPE_STRING: 30 | printf("STRING: %s\n", var->data.as_string); 31 | break; 32 | default: 33 | printf("UNKNOWN TYPE: %d", var->type); 34 | } 35 | } 36 | 37 | int main(int argc, char *argv[]) 38 | { 39 | Variant a_int = {.type = TYPE_INT, .data.as_integer = 100 }; 40 | Variant a_float = {.type = TYPE_FLOAT, .data.as_float = 100.34 }; 41 | Variant a_string = {.type = TYPE_STRING, 42 | .data.as_string = "YO DUDE!" }; 43 | 44 | Variant_print(&a_int); 45 | Variant_print(&a_float); 46 | Variant_print(&a_string); 47 | 48 | // here's how you access them 49 | a_int.data.as_integer = 200; 50 | a_float.data.as_float = 2.345; 51 | a_string.data.as_string = "Hi there."; 52 | 53 | Variant_print(&a_int); 54 | Variant_print(&a_float); 55 | Variant_print(&a_string); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /ex36/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex36/README.me -------------------------------------------------------------------------------- /ex36/ex36.c: -------------------------------------------------------------------------------- 1 | void copy(char to[], char from[]) 2 | { 3 | int i = 0; 4 | 5 | // while loop will not end if from isn't '\0' terminated 6 | while ((to[i] = from[i]) != '\0') { 7 | ++i; 8 | } 9 | } 10 | 11 | int safercopy(int from_len, char *from, int to_len, char *to) 12 | { 13 | int i = 0; 14 | int max = from_len > to_len - 1 ? to_len - 1 : from_len; 15 | 16 | // to_len must have at least 1 byte 17 | if (from_len < 0 || to_len <= 0) 18 | return -1; 19 | 20 | for (i = 0; i < max; i++) { 21 | to[i] = from[i]; 22 | } 23 | 24 | to[to_len - 1] = '\0'; 25 | 26 | return i; 27 | } 28 | -------------------------------------------------------------------------------- /ex36/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 36 5 | ---- 6 | 7 | Safer Strings 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Learn about an alternative string implementation to avoid most C string problems. 15 | 16 | 17 | 18 | C Strings Suck 19 | ==== 20 | 21 | It is impossible to safely process strings in C. 22 | 23 | 24 | 25 | The bstrling Library 26 | ==== 27 | 28 | An alternative is a library that provides alternative APIs for working with 29 | C strings. 30 | 31 | 32 | 33 | The Common Functions 34 | ==== 35 | 36 | bfromcstr Create a bstring from a C style constant. 37 | blk2bstr Do the same thing, but give the length of the buffer. 38 | bstrcpy Copy a bstring. 39 | bassign Set one bstring to another. 40 | bassigncstr Set a bstring to a C string's contents. 41 | bassignblk Set a bstring to a C string but give the length. 42 | bdestroy Destroy a bstring. 43 | bconcat Concatenate one bstring onto another. 44 | bstricmp Compare two bstrings returning the same result as strcmp. 45 | biseq Tests if two bstrings are equal. 46 | 47 | 48 | 49 | The Common Functions 50 | ==== 51 | 52 | binstr Tells if one bstring is in another. 53 | bfindreplace Find one bstring in another, then replace it with a third. 54 | bsplit Split a bstring into a bstrList. 55 | bformat Do a format string, which is super handy. 56 | blength Get the length of a bstring. 57 | bdata Get the data from a bstring. 58 | bchar Get a char from a bstring. 59 | 60 | 61 | 62 | Extra Credit 63 | ==== 64 | 65 | There is only one extra credit and that's to write a *tests/bstr_tests.c* file that 66 | tests all of these functions. The bstrlib comes with a test that you can reference it if needed. 67 | 68 | 69 | 70 | End Of Lecture 36 71 | ===== 72 | 73 | 74 | -------------------------------------------------------------------------------- /ex37/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex37/README.me -------------------------------------------------------------------------------- /ex38/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex38/README.me -------------------------------------------------------------------------------- /ex38/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 38 5 | ---- 6 | 7 | Hashmap Algorithms 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Learn three different string hashing algorithms and make them dynamically available 15 | to the Hashmap. 16 | 17 | 18 | 19 | Code Review 20 | ==== 21 | 22 | The default is the Jenkin's hash. 23 | 24 | You added the FNV1a, Adler32, and DJB hashing algorithms. 25 | 26 | Review the code for FNV1a vs. DJB. 27 | 28 | 29 | 30 | Breaking It 31 | ==== 32 | 33 | In this exercise you will attempt to write the worst hashing function that can 34 | pass for a real one. Try to make one that either looks complicated but 35 | statistically is way off, or is a discrete change to an existing one that is a 36 | bad change. 37 | 38 | 39 | 40 | Extra Credit 41 | ==== 42 | 43 | * Take the ``default_hash`` out of the ``hashmap.c``, make it 44 | one of the algorithms in ``hashmap_algos.c``, and then make all 45 | of the tests work again. 46 | * Add the ``default_hash`` to the ``hashmap_algos_tests.c`` 47 | test and compare its statistics to the other hash functions. 48 | * Find a few more hash functions and add them, too. You can never have too 49 | many hash functions! 50 | 51 | 52 | 53 | End Of Lecture 38 54 | ===== 55 | 56 | 57 | -------------------------------------------------------------------------------- /ex39/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex39/README.me -------------------------------------------------------------------------------- /ex4/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex4/README.me -------------------------------------------------------------------------------- /ex4/ex4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Warning: This program is wrong on purpose. */ 4 | 5 | int main() 6 | { 7 | int age = 10; 8 | int height; 9 | 10 | printf("I am %d years old.\n"); 11 | printf("I am %d inches tall.\n", height); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ex4/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 4 5 | ---- 6 | 7 | Using a Debugger 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * See how GDB works (LLDB on OSX). 15 | * Look at memory checkers like Valgrind and AddressSanitizer. 16 | * Cover the quick reference. 17 | * Debug a program. 18 | 19 | 20 | 21 | Using GDB 22 | ==== 23 | 24 | 25 | 26 | Using LLDB 27 | ==== 28 | 29 | 30 | 31 | Using Valgrind 32 | ==== 33 | 34 | 35 | 36 | Using Lint 37 | ==== 38 | 39 | 40 | 41 | Using AddressSanitizer 42 | ==== 43 | 44 | You neeed clang for this. 45 | 46 | 47 | 48 | "The Debugger" 49 | ==== 50 | 51 | When I say "the debugger" in the book I mean to use GDB, but use 52 | every tool you can find that helps. 53 | 54 | 55 | 56 | End Of Lecture 4 57 | ===== 58 | 59 | 60 | -------------------------------------------------------------------------------- /ex40/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex40/README.me -------------------------------------------------------------------------------- /ex41/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex41/README.me -------------------------------------------------------------------------------- /ex41/devpkg/DEPENDS: -------------------------------------------------------------------------------- 1 | http://mirror.metrocast.net/apache//apr/apr-1.5.2.tar.gz 2 | http://mirror.metrocast.net/apache//apr/apr-util-1.5.4.tar.gz 3 | -------------------------------------------------------------------------------- /ex41/devpkg/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX?=/usr/local 2 | CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 3 | CFLAGS+=-I${PREFIX}/apr/include/apr-util-1 4 | LDFLAGS=-L${PREFIX}/apr/lib -lapr-1 -pthread -laprutil-1 5 | 6 | all: devpkg 7 | 8 | devpkg: bstrlib.o db.o shell.o commands.o 9 | 10 | install: all 11 | install -d $(DESTDIR)/$(PREFIX)/bin/ 12 | install devpkg $(DESTDIR)/$(PREFIX)/bin/ 13 | 14 | clean: 15 | rm -f *.o 16 | rm -f devpkg 17 | rm -rf *.dSYM 18 | 19 | -------------------------------------------------------------------------------- /ex41/devpkg/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef _commands_h 2 | #define _commands_h 3 | 4 | #include 5 | 6 | #define DEPENDS_PATH "/tmp/DEPENDS" 7 | #define TAR_GZ_SRC "/tmp/pkg-src.tar.gz" 8 | #define TAR_BZ2_SRC "/tmp/pkg-src.tar.bz2" 9 | #define BUILD_DIR "/tmp/pkg-build" 10 | #define GIT_PAT "*.git" 11 | #define DEPEND_PAT "*DEPENDS" 12 | #define TAR_GZ_PAT "*.tar.gz" 13 | #define TAR_BZ2_PAT "*.tar.bz2" 14 | #define CONFIG_SCRIPT "/tmp/pkg-build/configure" 15 | 16 | enum CommandType { 17 | COMMAND_NONE, COMMAND_INSTALL, COMMAND_LIST, COMMAND_FETCH, 18 | COMMAND_INIT, COMMAND_BUILD 19 | }; 20 | 21 | int Command_fetch(apr_pool_t * p, const char *url, int fetch_only); 22 | 23 | int Command_install(apr_pool_t * p, const char *url, 24 | const char *configure_opts, const char *make_opts, 25 | const char *install_opts); 26 | 27 | int Command_depends(apr_pool_t * p, const char *path); 28 | 29 | int Command_build(apr_pool_t * p, const char *url, 30 | const char *configure_opts, const char *make_opts, 31 | const char *install_opts); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex41/devpkg/db.h: -------------------------------------------------------------------------------- 1 | #ifndef _db_h 2 | #define _db_h 3 | 4 | #define DB_FILE "/usr/local/.devpkg/db" 5 | #define DB_DIR "/usr/local/.devpkg" 6 | 7 | int DB_init(); 8 | int DB_list(); 9 | int DB_update(const char *url); 10 | int DB_find(const char *url); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /ex41/devpkg/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex41/devpkg/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef _shell_h 2 | #define _shell_h 3 | 4 | #define MAX_COMMAND_ARGS 100 5 | 6 | #include 7 | 8 | typedef struct Shell { 9 | const char *dir; 10 | const char *exe; 11 | 12 | apr_procattr_t *attr; 13 | apr_proc_t proc; 14 | apr_exit_why_e exit_why; 15 | int exit_code; 16 | 17 | const char *args[MAX_COMMAND_ARGS]; 18 | } Shell; 19 | 20 | int Shell_run(apr_pool_t * p, Shell * cmd); 21 | int Shell_exec(Shell cmd, ...); 22 | 23 | extern Shell CLEANUP_SH; 24 | extern Shell GIT_SH; 25 | extern Shell TAR_SH; 26 | extern Shell CURL_SH; 27 | extern Shell CONFIGURE_SH; 28 | extern Shell MAKE_SH; 29 | extern Shell INSTALL_SH; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /ex41/devpkg/test.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | rm -rf /usr/local/.devpkg 4 | 5 | # do a setup 6 | ./devpkg -S 7 | 8 | # regular tar.gz 9 | ./devpkg -I http://mirror.its.uidaho.edu/pub/apache//apr/apr-1.4.5.tar.gz 10 | 11 | # regular tar.bz2 12 | ./devpkg -I http://mongrel2.org/static/downloads/mongrel2-1.7.5.tar.bz2 13 | 14 | # regular .git 15 | ./devpkg -I https://github.com/zedshaw/srpmin.git 16 | 17 | # manually fetch/build if already installed 18 | ./devpkg -F https://github.com/zedshaw/srpmin.git 19 | 20 | ./devpkg -B https://github.com/zedshaw/srpmin.git 21 | 22 | # manually fetch/build it not installed 23 | ./devpkg -F http://mirror.its.uidaho.edu/pub/apache//apr/apr-util-1.3.12.tar.gz 24 | 25 | ./devpkg -B http://mirror.its.uidaho.edu/pub/apache//apr/apr-util-1.3.12.tar.gz -c "--with-apr=/usr/local/apr" 26 | 27 | # idempotent build test 28 | ./devpkg -I http://mirror.its.uidaho.edu/pub/apache//apr/apr-util-1.3.12.tar.gz -c "--with-apr=/usr/local/apr" 29 | 30 | 31 | # just run the depends, nothing should build 32 | ./devpkg -I ./DEPENDS 33 | 34 | # list out what's installed 35 | ./devpkg -L 36 | 37 | -------------------------------------------------------------------------------- /ex41/ex41.1.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # go somewhere safe 4 | cd /tmp 5 | 6 | # get the source to base APR 1.5.2 7 | curl -L -O http://archive.apache.org/dist/apr/apr-1.5.2.tar.gz 8 | 9 | # extract it and go into the source 10 | tar -xzvf apr-1.5.2.tar.gz 11 | cd apr-1.5.2 12 | 13 | # you need this on OSX Yosemite 14 | touch libtoolT 15 | 16 | # configure, make, make install 17 | ./configure 18 | make 19 | sudo make install 20 | 21 | # reset and cleanup 22 | cd /tmp 23 | rm -rf apr-1.5.2 apr-1.5.2.tar.gz 24 | 25 | # do the same with apr-util 26 | curl -L -O http://archive.apache.org/dist/apr/apr-util-1.5.4.tar.gz 27 | 28 | # extract 29 | tar -xzvf apr-util-1.5.4.tar.gz 30 | cd apr-util-1.5.4 31 | 32 | # you need this on OSX Yosemite 33 | touch libtoolT 34 | 35 | # configure, make, make install 36 | ./configure --with-apr=/usr/local/apr 37 | # you need that extra parameter to configure because 38 | # apr-util can't really find it because...who knows. 39 | 40 | make 41 | sudo make install 42 | 43 | #cleanup 44 | cd /tmp 45 | rm -rf apr-util-1.5.4* apr-1.5.2* 46 | 47 | -------------------------------------------------------------------------------- /ex41/ex41.2.sh: -------------------------------------------------------------------------------- 1 | mkdir devpkg 2 | cd devpkg 3 | touch README Makefile 4 | -------------------------------------------------------------------------------- /ex41/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 41 5 | ---- 6 | 7 | Project devpkg 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Create a handy little tool called devpkg. 15 | 16 | This will be a *lot* of work, so this video is more complete. 17 | 18 | 19 | 20 | Demonstration 21 | ==== 22 | 23 | I'll demonstrate how devpkg works so you get a better idea. 24 | 25 | Read the book's description as well for more details. 26 | 27 | 28 | 29 | The Apache Portable Runtime 30 | ==== 31 | 32 | Review of the APR and installing it. 33 | 34 | 35 | 36 | The Analysis 37 | ==== 38 | 39 | Walk through the code, where everything is, and what to watch out for. 40 | 41 | 42 | 43 | Getting My Code 44 | ==== 45 | 46 | If you get stuck you can check out the learn-c-the-hard-way-lectures project: 47 | 48 | https://github.com/zedshaw/learn-c-the-hard-way-lectures 49 | 50 | And look in ex41/devpkg for the code. 51 | 52 | 53 | 54 | Extra Credit 55 | ==== 56 | 57 | * Compare your code to my code available online. Starting with 100%, 58 | remove 1% for each line you got wrong. 59 | * Take the notes.txt file that you previously created and implement your improvements to the the code and functionality 60 | of ``devpkg``. 61 | * Write an alternative version of ``devpkg`` using your other 62 | favorite language or the one you think can do this the best. Compare 63 | the two, then improve your *C* version of ``devpkg`` based on what 64 | you've learned. 65 | 66 | 67 | 68 | End Of Lecture 41 69 | ===== 70 | 71 | 72 | -------------------------------------------------------------------------------- /ex42/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex42/README.me -------------------------------------------------------------------------------- /ex42/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 42 5 | ---- 6 | 7 | Stacks and Queues 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Create a Stack and Queue data structure from just the unit tests. 15 | 16 | 17 | 18 | PAUSE! 19 | ==== 20 | 21 | WARNING! Stop the video now and try to solve this yourself! 22 | 23 | I'll show you how I did it after you try it (or you can cheat). 24 | 25 | 26 | 27 | Code Review 28 | ==== 29 | 30 | 31 | 32 | Extra Credit 33 | ==== 34 | 35 | * Implement ``Stack`` using ``DArray`` instead of ``List``, but without changing the unit test. That means you'll have to create your own ``STACK_FOREACH``. 36 | 37 | 38 | 39 | End Of Lecture 42 40 | ===== 41 | 42 | 43 | -------------------------------------------------------------------------------- /ex43/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex43/README.me -------------------------------------------------------------------------------- /ex43/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 43 5 | ---- 6 | 7 | A Simple Statistics Engine 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * A fun and handy little statistics engine for simple analysis. 15 | * Comparing it to the same in R. 16 | 17 | 18 | 19 | Comparing Test vs. R 20 | ==== 21 | 22 | I'll use R to show you how this works vs. normal calculations using all data. 23 | 24 | 25 | 26 | Breaking It 27 | ==== 28 | 29 | Easiest way to break this is to just feed it bad data once then the whole 30 | stream is broken. 31 | 32 | 33 | 34 | Extra Credit 35 | ==== 36 | 37 | * Convert the ``Stats_stddev`` and ``Stats_mean`` to ``static inline`` functions in the ``stats.h`` file instead of in the ``stats.c`` file. 38 | * Use this code to write a performance test of the ``string_algos_test.c``. 39 | Make it optional, and have it run the base test as a series of samples, and then report 40 | the results. 41 | * Write a version of this in another programming language you know. Confirm that this 42 | version is correct based on what I have here. 43 | 44 | 45 | 46 | Extra Credit 47 | ==== 48 | 49 | * Write a little program that can take a file full of numbers and spit these statistics 50 | out for them. 51 | * Make the program accept a table of data that has headers on one line, then all 52 | of the other numbers on lines after it are separated by any number of spaces. Your program 53 | should then print out these statistics for each column by the header name. 54 | 55 | 56 | 57 | End Of Lecture 43 58 | ===== 59 | 60 | 61 | -------------------------------------------------------------------------------- /ex44/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex44/README.me -------------------------------------------------------------------------------- /ex44/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 44 5 | ---- 6 | 7 | Ring Buffer 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Learn about a handy data structure for I/O processing: 15 | 16 | Ring Buffers 17 | 18 | 19 | 20 | The Code 21 | ==== 22 | 23 | It's basically a DArray with dynamic start and end settings. 24 | You can *also* use a Queue of bstrings to do almost the same thing. 25 | 26 | 27 | 28 | Code Review 29 | ==== 30 | 31 | 32 | 33 | The Analysis 34 | ==== 35 | 36 | * Watch a ring buffer work in the debugger. 37 | * Draw it visually to explore it. 38 | * The purpose is to efficiently add and remove data when the amount added and removed is random. 39 | 40 | 41 | 42 | Pause! 43 | ==== 44 | 45 | I will next review the unit test I wrote so if you want to attempt 46 | solving it yourself then pause now. 47 | 48 | 49 | 50 | The Unit Test 51 | ==== 52 | 53 | Here's my version of the unit test. 54 | 55 | 56 | 57 | Breaking It 58 | ==== 59 | 60 | * The biggest mistake you'll make with a ring buffer is off-by-one errors. 61 | * This is why the RingBuffer\_commit\_ and other macros exist. 62 | * Another common mistake is to use it between threads, but that's a whole other book. 63 | 64 | 65 | 66 | Extra Credit 67 | ==== 68 | 69 | * Create an alternative implementation of ``RingBuffer`` that uses 70 | the POSIX trick and a unit test for it. 71 | * Add a performance comparison test to this unit test that compares the 72 | two versions by fuzzing them with random data and random read/write operations. 73 | Make sure that you set up this fuzzing so that the same operations are done 74 | to each version, and you can compare them between runs. 75 | 76 | 77 | 78 | End Of Lecture 44 79 | ===== 80 | 81 | 82 | -------------------------------------------------------------------------------- /ex45/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex45/README.me -------------------------------------------------------------------------------- /ex45/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 45 5 | ---- 6 | 7 | A Simple TCP/IP Client 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn to use the *select* method and a RingBuffer to write a simple command line network client. 15 | 16 | 17 | How select Works 18 | ==== 19 | 20 | 21 | 22 | Code Review 23 | ==== 24 | 25 | 26 | 27 | Improving It 28 | ==== 29 | 30 | These read functions are useful so I can put them in RingBuffer. 31 | 32 | 33 | 34 | Extra Credit 35 | ==== 36 | 37 | * As I mentioned, there are quite a few functions you may not know, so 38 | look them up. In fact, look them all up even if you think you know 39 | them. 40 | * Go back through and add various defensive programming checks to 41 | the functions to improve them. 42 | * Use the *getopt* function to allow the user 43 | the option *not* to translate *\n* to *\r\n*. This 44 | is only needed on protocols that require it for line endings, like HTTP. 45 | Sometimes you don't want the translation, so give the user the option. 46 | 47 | 48 | 49 | End Of Lecture 45 50 | ===== 51 | 52 | 53 | -------------------------------------------------------------------------------- /ex46/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex46/README.me -------------------------------------------------------------------------------- /ex46/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 46 5 | ---- 6 | 7 | Ternary Search Tree 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Learn about my favorite data structure ever: 15 | 16 | Ternary Search Tree 17 | 18 | 19 | 20 | The Code 21 | ==== 22 | 23 | Similar to a Binary Search Tree, but it has 3 branches per node based on 24 | the characters in strings. 25 | 26 | 27 | 28 | Advantages 29 | ==== 30 | 31 | * Find any string comparing at most N characters. 32 | * Detect *missing* strings as fast, usually faster. 33 | * Find all strings that start with, or contain, any substring as fast. 34 | * Find all similar known strings quickly. 35 | 36 | 37 | 38 | Disadvantages 39 | ==== 40 | 41 | * Delete is a pain, as in most trees. 42 | * Uses lots of memory to store keys, so bad for sets of large keys. 43 | * Kind of weird for most programmers. 44 | 45 | 46 | 47 | Improving It 48 | === 49 | 50 | * You could allow duplicates by using a *DArray* instead of the 51 | *value*. 52 | * As I mentioned earlier, deleting is hard, but you could simulate it by setting 53 | the values to *NULL* so that they are effectively gone. 54 | * There are no ways to collect all of the possible matching values. I'll have 55 | you implement that in an extra credit. 56 | * There are other algorithms that are more complex but have slightly 57 | better properties. Take a look at suffix array, suffix tree, and 58 | radix tree structures. 59 | 60 | 61 | 62 | Extra Credit 63 | ==== 64 | 65 | * Implement a *TSTree_collect* that returns a *DArray* containing 66 | all of the keys that match the given prefix. 67 | * Implement *TSTree_search_suffix* and a *TSTree_insert_suffix* 68 | so you can do suffix searches and inserts. 69 | * Use the debugger to see how this structure is used in memory 70 | compared to the *BSTree* and *Hashmap*. 71 | 72 | 73 | 74 | End Of Lecture 46 75 | ===== 76 | 77 | 78 | -------------------------------------------------------------------------------- /ex47/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex47/README.me -------------------------------------------------------------------------------- /ex47/ex47_urls.txt: -------------------------------------------------------------------------------- 1 | /test.tst TestHandler 2 | / IndexHandler 3 | /test/this/out/index.html PageHandler 4 | /index.html PageHandler 5 | /and/then/i/have/things/to/test.html PageHandler 6 | -------------------------------------------------------------------------------- /ex47/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 47 5 | ---- 6 | 7 | A Fast URL Router 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Use the *TSTree* to do something useful: 15 | 16 | Route URLs 17 | 18 | 19 | 20 | Code Review 21 | ==== 22 | 23 | 24 | 25 | The Analysis 26 | ==== 27 | 28 | Watch me play with it and then tell you how it's working. 29 | 30 | 31 | 32 | Improving It 33 | ==== 34 | 35 | * Collect all possible matches then choose the longest as winner. 36 | * Use TSTree to find prefixes, then regex to choose winner. 37 | 38 | 39 | 40 | Extra Credit 41 | ==== 42 | 43 | * Instead of just storing the string for the handler, create an actual engine that uses a 44 | *Handler* struct to store the application. The structure would store the URL to which it's attached, the name, and anything else you'd need to make an actual routing system. 45 | 46 | 47 | 48 | Extra Credit 49 | ==== 50 | 51 | * Instead of mapping URLs to arbitrary names, map them to .so files and use the *dlopen* 52 | system to load handlers on the fly and call callbacks they contain. Put these callbacks that 53 | in your *Handler* struct, and then you have yourself a fully dynamic callback 54 | handler system in C. 55 | 56 | 57 | 58 | End Of Lecture 47 59 | ===== 60 | 61 | 62 | -------------------------------------------------------------------------------- /ex48a/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex48a/README.me -------------------------------------------------------------------------------- /ex48b/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex48b/README.me -------------------------------------------------------------------------------- /ex48b/c-skeleton/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex48b/c-skeleton/LICENSE -------------------------------------------------------------------------------- /ex48b/c-skeleton/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS) 2 | LIBS=-ldl $(OPTLIBS) 3 | PREFIX?=/usr/local 4 | 5 | SOURCES=$(wildcard src/**/*.c src/*.c) 6 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 7 | 8 | TEST_SRC=$(wildcard tests/*_tests.c) 9 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 10 | 11 | TARGET=build/libYOUR_LIBRARY.a 12 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 13 | 14 | # The Target Build 15 | all: $(TARGET) $(SO_TARGET) tests 16 | 17 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 18 | dev: all 19 | 20 | $(TARGET): CFLAGS += -fPIC 21 | $(TARGET): build $(OBJECTS) 22 | ar rcs $@ $(OBJECTS) 23 | ranlib $@ 24 | 25 | $(SO_TARGET): $(TARGET) $(OBJECTS) 26 | $(CC) -shared -o $@ $(OBJECTS) 27 | 28 | build: 29 | @mkdir -p build 30 | @mkdir -p bin 31 | 32 | # The Unit Tests 33 | .PHONY: tests 34 | tests: CFLAGS += $(TARGET) 35 | tests: $(TESTS) 36 | sh ./tests/runtests.sh 37 | 38 | # The Cleaner 39 | clean: 40 | rm -rf build $(OBJECTS) $(TESTS) 41 | rm -f tests/tests.log 42 | find . -name "*.gc*" -exec rm {} \; 43 | rm -rf `find . -name "*.dSYM" -print` 44 | 45 | # The Install 46 | install: all 47 | install -d $(DESTDIR)/$(PREFIX)/lib/ 48 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 49 | 50 | # The Checker 51 | check: 52 | @echo Files with potentially dangerous functions. 53 | @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ 54 | |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true 55 | 56 | -------------------------------------------------------------------------------- /ex48b/c-skeleton/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex48b/c-skeleton/README.md -------------------------------------------------------------------------------- /ex48b/c-skeleton/src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex48b/c-skeleton/src/libex29.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dbg.h" 4 | 5 | 6 | int print_a_message(const char *msg) 7 | { 8 | printf("A STRING: %s\n", msg); 9 | 10 | return 0; 11 | } 12 | 13 | 14 | int uppercase(const char *msg) 15 | { 16 | int i = 0; 17 | 18 | // BUG: \0 termination problems 19 | for(i = 0; msg[i] != '\0'; i++) { 20 | printf("%c", toupper(msg[i])); 21 | } 22 | 23 | printf("\n"); 24 | 25 | return 0; 26 | } 27 | 28 | int lowercase(const char *msg) 29 | { 30 | int i = 0; 31 | 32 | // BUG: \0 termination problems 33 | for(i = 0; msg[i] != '\0'; i++) { 34 | printf("%c", tolower(msg[i])); 35 | } 36 | 37 | printf("\n"); 38 | 39 | return 0; 40 | } 41 | 42 | int fail_on_purpose(const char *msg) 43 | { 44 | return 1; 45 | } 46 | -------------------------------------------------------------------------------- /ex48b/c-skeleton/tests/libex29_tests.c: -------------------------------------------------------------------------------- 1 | #include "minunit.h" 2 | #include 3 | 4 | typedef int (*lib_function) (const char *data); 5 | char *lib_file = "build/libYOUR_LIBRARY.so"; 6 | void *lib = NULL; 7 | 8 | int check_function(const char *func_to_run, const char *data, 9 | int expected) 10 | { 11 | lib_function func = dlsym(lib, func_to_run); 12 | check(func != NULL, 13 | "Did not find %s function in the library %s: %s", func_to_run, 14 | lib_file, dlerror()); 15 | 16 | int rc = func(data); 17 | check(rc == expected, "Function %s return %d for data: %s", 18 | func_to_run, rc, data); 19 | 20 | return 1; 21 | error: 22 | return 0; 23 | } 24 | 25 | char *test_dlopen() 26 | { 27 | lib = dlopen(lib_file, RTLD_NOW); 28 | mu_assert(lib != NULL, "Failed to open the library to test."); 29 | 30 | return NULL; 31 | } 32 | 33 | char *test_functions() 34 | { 35 | mu_assert(check_function("print_a_message", "Hello", 0), 36 | "print_a_message failed."); 37 | mu_assert(check_function("uppercase", "Hello", 0), 38 | "uppercase failed."); 39 | mu_assert(check_function("lowercase", "Hello", 0), 40 | "lowercase failed."); 41 | 42 | return NULL; 43 | } 44 | 45 | char *test_failures() 46 | { 47 | mu_assert(check_function("fail_on_purpose", "Hello", 1), 48 | "fail_on_purpose should fail."); 49 | 50 | return NULL; 51 | } 52 | 53 | char *test_dlclose() 54 | { 55 | int rc = dlclose(lib); 56 | mu_assert(rc == 0, "Failed to close lib."); 57 | 58 | return NULL; 59 | } 60 | 61 | char *all_tests() 62 | { 63 | mu_suite_start(); 64 | 65 | mu_run_test(test_dlopen); 66 | mu_run_test(test_functions); 67 | mu_run_test(test_failures); 68 | mu_run_test(test_dlclose); 69 | 70 | return NULL; 71 | } 72 | 73 | RUN_TESTS(all_tests); 74 | -------------------------------------------------------------------------------- /ex48b/c-skeleton/tests/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) {\ 12 | log_err(message); return message; } 13 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 14 | message = test(); tests_run++; if (message) return message; 15 | 16 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 17 | argc = 1; \ 18 | debug("----- RUNNING: %s", argv[0]);\ 19 | printf("----\nRUNNING: %s\n", argv[0]);\ 20 | char *result = name();\ 21 | if (result != 0) {\ 22 | printf("FAILED: %s\n", result);\ 23 | }\ 24 | else {\ 25 | printf("ALL TESTS PASSED\n");\ 26 | }\ 27 | printf("Tests run: %d\n", tests_run);\ 28 | exit(result != 0);\ 29 | } 30 | 31 | int tests_run; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex48b/c-skeleton/tests/runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in tests/*_tests 4 | do 5 | if test -f $i 6 | then 7 | if $VALGRIND ./$i 2>> tests/tests.log 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i: here's tests/tests.log" 12 | echo "------" 13 | tail tests/tests.log 14 | exit 1 15 | fi 16 | fi 17 | done 18 | 19 | echo "" 20 | -------------------------------------------------------------------------------- /ex48b/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 48 5 | ---- 6 | 7 | A Simple Network Server: 8 | 9 | Solution 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | Show you how I solved the *statserve* project. 18 | 19 | 20 | 21 | The Purpose 22 | ==== 23 | 24 | Watch me solve the first project quickly, then review the code. 25 | 26 | 27 | 28 | The Setup 29 | ==== 30 | 31 | First I need to install liblcthw since I'll be using that. 32 | 33 | Then I make the project skeleton and get something, anything going. 34 | 35 | 36 | 37 | The Server 38 | ==== 39 | 40 | Then I just get it accepting a connection. 41 | 42 | 43 | 44 | The Echo 45 | ==== 46 | 47 | Then I decided to just make it echo back what I type. 48 | 49 | 50 | 51 | The Final Code 52 | ==== 53 | 54 | 55 | 56 | End Of Lecture 48b 57 | ===== 58 | 59 | 60 | -------------------------------------------------------------------------------- /ex48b/statserve/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dSYM 3 | *.so 4 | .*.sw* 5 | *.log 6 | build/* 7 | tests/*_tests 8 | bin/statserve 9 | -------------------------------------------------------------------------------- /ex48b/statserve/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex48b/statserve/LICENSE -------------------------------------------------------------------------------- /ex48b/statserve/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O2 -Wall -Wextra -I/usr/local/include -Isrc -rdynamic $(OPTFLAGS) 2 | LIBS=-llcthw $(OPTLIBS) 3 | LDFLAGS=-L/usr/local/lib $(LIBS) 4 | PREFIX?=/usr/local 5 | 6 | SOURCES=$(wildcard src/**/*.c src/*.c) 7 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 8 | 9 | TEST_SRC=$(wildcard tests/*_tests.c) 10 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 11 | 12 | TARGET=build/libstatserve.a 13 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 14 | 15 | # The Target Build 16 | all: $(TARGET) $(SO_TARGET) tests bin/statserve 17 | 18 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 19 | dev: all 20 | 21 | bin/statserve: $(TARGET) 22 | 23 | $(TARGET): CFLAGS += -fPIC 24 | $(TARGET): build $(OBJECTS) 25 | ar rcs $@ $(OBJECTS) 26 | ranlib $@ 27 | 28 | $(SO_TARGET): $(TARGET) $(OBJECTS) 29 | $(CC) -shared -o $@ $(LDFLAGS) $(LIBS) $(OBJECTS) 30 | 31 | build: 32 | @mkdir -p build 33 | @mkdir -p bin 34 | 35 | # The Unit Tests 36 | .PHONY: tests 37 | tests: CFLAGS += $(TARGET) 38 | tests: $(TESTS) 39 | sh ./tests/runtests.sh 40 | 41 | # The Cleaner 42 | clean: 43 | rm -rf build $(OBJECTS) $(TESTS) 44 | rm -f tests/tests.log 45 | find . -name "*.gc*" -exec rm {} \; 46 | rm -rf `find . -name "*.dSYM" -print` 47 | 48 | # The Install 49 | install: all 50 | install -d $(DESTDIR)/$(PREFIX)/lib/ 51 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 52 | 53 | # The Checker 54 | check: 55 | @echo Files with potentially dangerous functions. 56 | @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ 57 | |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true 58 | 59 | -------------------------------------------------------------------------------- /ex48b/statserve/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex48b/statserve/README.md -------------------------------------------------------------------------------- /ex48b/statserve/bin/statserve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "statserve.h" 4 | #include "net.h" 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | check(argc == 3, "USAGE: statserve host port"); 10 | 11 | const char *host = argv[1]; 12 | const char *port = argv[2]; 13 | 14 | check(echo_server(host, port), "Failed to run the echo server."); 15 | 16 | return 0; 17 | 18 | error: 19 | 20 | return 1; 21 | } 22 | -------------------------------------------------------------------------------- /ex48b/statserve/src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex48b/statserve/src/net.h: -------------------------------------------------------------------------------- 1 | #ifndef _net_h 2 | #define _net_h 3 | 4 | #include 5 | 6 | #define BACKLOG 10 7 | 8 | int nonblock(int fd); 9 | int client_connect(char *host, char *port); 10 | int read_some(RingBuffer * buffer, int fd, int is_socket); 11 | int write_some(RingBuffer * buffer, int fd, int is_socket); 12 | int server_listen(const char *host, const char *port); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /ex48b/statserve/src/statserve.h: -------------------------------------------------------------------------------- 1 | #ifndef _statserve_h 2 | #define _statserve_h 3 | 4 | int echo_server(const char *host, const char *port); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /ex48b/statserve/tests/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) {\ 12 | log_err(message); return message; } 13 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 14 | message = test(); tests_run++; if (message) return message; 15 | 16 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 17 | argc = 1; \ 18 | debug("----- RUNNING: %s", argv[0]);\ 19 | printf("----\nRUNNING: %s\n", argv[0]);\ 20 | char *result = name();\ 21 | if (result != 0) {\ 22 | printf("FAILED: %s\n", result);\ 23 | }\ 24 | else {\ 25 | printf("ALL TESTS PASSED\n");\ 26 | }\ 27 | printf("Tests run: %d\n", tests_run);\ 28 | exit(result != 0);\ 29 | } 30 | 31 | int tests_run; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex48b/statserve/tests/runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in tests/*_tests 4 | do 5 | if test -f $i 6 | then 7 | if $VALGRIND ./$i 2>> tests/tests.log 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i: here's tests/tests.log" 12 | echo "------" 13 | tail tests/tests.log 14 | exit 1 15 | fi 16 | fi 17 | done 18 | 19 | echo "" 20 | -------------------------------------------------------------------------------- /ex48b/statserve/tests/statserve_tests.c: -------------------------------------------------------------------------------- 1 | #include "minunit.h" 2 | #include 3 | #include "statserve.h" 4 | 5 | char *test_dummy() 6 | { 7 | return NULL; 8 | } 9 | 10 | char *all_tests() 11 | { 12 | mu_suite_start(); 13 | 14 | mu_run_test(test_dummy); 15 | 16 | return NULL; 17 | } 18 | 19 | RUN_TESTS(all_tests); 20 | -------------------------------------------------------------------------------- /ex49a/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex49a/README.me -------------------------------------------------------------------------------- /ex49b/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex49b/README.me -------------------------------------------------------------------------------- /ex49b/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 49 5 | ---- 6 | 7 | A Statistics Server: 8 | 9 | Solution 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | I'll show you how I implemented the protocol in the smallest code possible. 18 | 19 | I won't implement all of the CRUD operations, so you can go look at the 20 | git repo for this project to see a full implementation. 21 | 22 | 23 | 24 | The Setup 25 | ==== 26 | 27 | First I setup the data, then the protocol parser, then the handlers. 28 | 29 | 30 | 31 | The Protocol 32 | ==== 33 | 34 | create Create a new statistic. 35 | mean Get the current mean of a statistic. 36 | sample Add a new sample to a statistics. 37 | dump Get all of the elements of a statistic (sum, sumsq, n, min, and max).Final Code 38 | 39 | 40 | 41 | The Command Structure 42 | ==== 43 | 44 | typedef struct Command { 45 | bstring command; 46 | bstring name; 47 | bstring number; 48 | handler_cb handler; 49 | } Command; 50 | 51 | 52 | 53 | The Storage Record 54 | ==== 55 | 56 | typedef struct Record { 57 | bstring name; 58 | Stats *stat; 59 | } Record; 60 | 61 | 62 | 63 | The Design 64 | ==== 65 | 66 | * Accept a connection 67 | * Parse the line into the Command 68 | * Run a handler function to process it 69 | * Temporarily store into a Hashmap 70 | 71 | 72 | 73 | Final Thoughts 74 | ==== 75 | 76 | The last thing I would do is add better tests and round out the protocol with CRUD operations. 77 | 78 | 79 | 80 | End Of Lecture 49b 81 | ===== 82 | 83 | 84 | -------------------------------------------------------------------------------- /ex49b/statserve/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dSYM 3 | *.so 4 | .*.sw* 5 | *.log 6 | build/* 7 | tests/*_tests 8 | bin/statserve 9 | -------------------------------------------------------------------------------- /ex49b/statserve/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex49b/statserve/LICENSE -------------------------------------------------------------------------------- /ex49b/statserve/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O2 -Wall -Wextra -I/usr/local/include -Isrc -rdynamic $(OPTFLAGS) 2 | LIBS=-llcthw $(OPTLIBS) 3 | LDFLAGS=-L/usr/local/lib $(LIBS) 4 | PREFIX?=/usr/local 5 | 6 | SOURCES=$(wildcard src/**/*.c src/*.c) 7 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 8 | 9 | TEST_SRC=$(wildcard tests/*_tests.c) 10 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 11 | 12 | TARGET=build/libstatserve.a 13 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 14 | 15 | # The Target Build 16 | all: $(TARGET) $(SO_TARGET) tests bin/statserve 17 | 18 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 19 | dev: all 20 | 21 | bin/statserve: $(TARGET) 22 | 23 | $(TARGET): CFLAGS += -fPIC 24 | $(TARGET): build $(OBJECTS) 25 | ar rcs $@ $(OBJECTS) 26 | ranlib $@ 27 | 28 | $(SO_TARGET): $(TARGET) $(OBJECTS) 29 | $(CC) -shared -o $@ $(LDFLAGS) $(LIBS) $(OBJECTS) 30 | 31 | build: 32 | @mkdir -p build 33 | @mkdir -p bin 34 | 35 | # The Unit Tests 36 | .PHONY: tests 37 | tests: CFLAGS += $(TARGET) 38 | tests: $(TESTS) 39 | sh ./tests/runtests.sh 40 | 41 | # The Cleaner 42 | clean: 43 | rm -rf build $(OBJECTS) $(TESTS) 44 | rm -f tests/tests.log 45 | find . -name "*.gc*" -exec rm {} \; 46 | rm -rf `find . -name "*.dSYM" -print` 47 | 48 | # The Install 49 | install: all 50 | install -d $(DESTDIR)/$(PREFIX)/lib/ 51 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 52 | 53 | # The Checker 54 | check: 55 | @echo Files with potentially dangerous functions. 56 | @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ 57 | |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true 58 | 59 | -------------------------------------------------------------------------------- /ex49b/statserve/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex49b/statserve/README.md -------------------------------------------------------------------------------- /ex49b/statserve/bin/statserve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "statserve.h" 4 | #include "net.h" 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | check(argc == 3, "USAGE: statserve host port"); 10 | 11 | const char *host = argv[1]; 12 | const char *port = argv[2]; 13 | 14 | check(echo_server(host, port), "Failed to run the echo server."); 15 | 16 | return 0; 17 | 18 | error: 19 | 20 | return 1; 21 | } 22 | -------------------------------------------------------------------------------- /ex49b/statserve/src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex49b/statserve/src/net.h: -------------------------------------------------------------------------------- 1 | #ifndef _net_h 2 | #define _net_h 3 | 4 | #include 5 | 6 | #define BACKLOG 10 7 | 8 | int nonblock(int fd); 9 | int client_connect(char *host, char *port); 10 | int read_some(RingBuffer * buffer, int fd, int is_socket); 11 | int write_some(RingBuffer * buffer, int fd, int is_socket); 12 | int server_listen(const char *host, const char *port); 13 | bstring read_line(RingBuffer *input, const char line_ending); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /ex49b/statserve/src/statserve.h: -------------------------------------------------------------------------------- 1 | #ifndef _statserve_h 2 | #define _statserve_h 3 | 4 | #include 5 | #include 6 | 7 | struct tagbstring OK; 8 | 9 | int setup_data_store(); 10 | 11 | int parse_line(bstring data, RingBuffer *send_rb); 12 | 13 | int echo_server(const char *host, const char *port); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /ex49b/statserve/tests/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) {\ 12 | log_err(message); return message; } 13 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 14 | message = test(); tests_run++; if (message) return message; 15 | 16 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 17 | argc = 1; \ 18 | debug("----- RUNNING: %s", argv[0]);\ 19 | printf("----\nRUNNING: %s\n", argv[0]);\ 20 | char *result = name();\ 21 | if (result != 0) {\ 22 | printf("FAILED: %s\n", result);\ 23 | }\ 24 | else {\ 25 | printf("ALL TESTS PASSED\n");\ 26 | }\ 27 | printf("Tests run: %d\n", tests_run);\ 28 | exit(result != 0);\ 29 | } 30 | 31 | int tests_run; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex49b/statserve/tests/runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in tests/*_tests 4 | do 5 | if test -f $i 6 | then 7 | if $VALGRIND ./$i 2>> tests/tests.log 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i: here's tests/tests.log" 12 | echo "------" 13 | tail tests/tests.log 14 | exit 1 15 | fi 16 | fi 17 | done 18 | 19 | echo "" 20 | -------------------------------------------------------------------------------- /ex5/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex5/README.me -------------------------------------------------------------------------------- /ex50a/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex50a/README.me -------------------------------------------------------------------------------- /ex50a/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 50 5 | ---- 6 | 7 | Routing The Statistics 8 | 9 | Project Description 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | You are now given vague instructions and have to "solve" as best you can. 18 | 19 | 20 | 21 | The Purpose 22 | ==== 23 | 24 | To give you freedom to be creative, and also taste a real project with vague 25 | specifications. 26 | 27 | Many times all you get is a single sentence in a bug tracker. Oh well. 28 | 29 | 30 | 31 | The Requirements 32 | ==== 33 | 34 | Allow people to work with statistics at arbitrary URLs in the server. 35 | You get to define what that means, but think "web application". 36 | 37 | 38 | 39 | Pause! 40 | ==== 41 | 42 | Try to solve it on your own then continue. 43 | 44 | 45 | 46 | The Clues 47 | ==== 48 | 49 | Answer these questions: 50 | 51 | 1. What happens when I have a statistics "under" another, as in /age/northamerica/ is under /age/. 52 | 2. Could you do the summary statistics we talked about? A mean of means and mean of standard deviations that are rolled up the tree? 53 | 3. What data structures do you need? Starting with data is key here too. Data data data. 54 | 4. Are your tests good enough? Before you start you might want to get good tests that use the protocol. 55 | 56 | 57 | 58 | Important References 59 | ==== 60 | 61 | * Definitely look at the statistics code you built in liblcthw if you do the summary statistics. 62 | 63 | 64 | 65 | Encouragement 66 | ==== 67 | 68 | This is hard, as I've said all along, however it is all doable. It's simply a matter of breaking the problems down and tackling each little piece. 69 | 70 | 71 | 72 | End Of Lecture 50a 73 | ===== 74 | 75 | 76 | -------------------------------------------------------------------------------- /ex50b/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex50b/README.me -------------------------------------------------------------------------------- /ex50b/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 50 5 | ---- 6 | 7 | Routing the Statistics 8 | 9 | Solution 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | Show you how I solved the problem of routing the names of statistics as URLs. 18 | 19 | 20 | 21 | The Setup 22 | ==== 23 | 24 | 1. First thing I did was make sure my tests were really good. 25 | 2. Then I designed the data structures I'd need. 26 | 3. Then I did the work to make them functions. 27 | 4. The protocol shouldn't need to change. 28 | 29 | 30 | 31 | "URLs" 32 | ==== 33 | 34 | I'll define paths as simply names separated by /. 35 | 36 | Real URLs are way more complex than that. 37 | 38 | 39 | 40 | Data Structure 41 | ==== 42 | 43 | I just added: 44 | 45 | struct bstrList *path; 46 | 47 | To the Command struct to hold paths. 48 | 49 | 50 | 51 | URL Meaning 52 | ==== 53 | 54 | Kind of weird, but: 55 | 56 | Deepest part of URL is "parent", this is the main stat. 57 | Children are next segments up, and are mean-of-mean stats. 58 | 59 | 60 | 61 | New Processing 62 | ==== 63 | 64 | 1. Change to a loop over all paths with a "scan path" function. 65 | 2. Add optional path parameter to handlers. 66 | 3. Parse the path in *parse\_command* to set path in Commands. 67 | 4. In sample and create, change root processing vs. child processing. 68 | 5. Move *send\_reply* over to *net.c* instead. 69 | 70 | 71 | 72 | Test First Path Parsing 73 | ==== 74 | 75 | I'll write a small test for just the *scan\_paths* part first. 76 | 77 | Then wire that in and use the existing tests to confirm the old code 78 | works. 79 | 80 | 81 | 82 | The Code 83 | ==== 84 | 85 | 86 | 87 | Final Review 88 | ==== 89 | 90 | 91 | 92 | End Of Lecture 50b 93 | ===== 94 | 95 | 96 | -------------------------------------------------------------------------------- /ex50b/statserve/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dSYM 3 | *.so 4 | .*.sw* 5 | *.log 6 | build/* 7 | tests/*_tests 8 | -------------------------------------------------------------------------------- /ex50b/statserve/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex50b/statserve/LICENSE -------------------------------------------------------------------------------- /ex50b/statserve/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O2 -Wall -Wextra -I/usr/local/include -Isrc -rdynamic $(OPTFLAGS) 2 | LIBS=-llcthw $(OPTLIBS) 3 | LDFLAGS=-L/usr/local/lib $(LIBS) 4 | PREFIX?=/usr/local 5 | 6 | SOURCES=$(wildcard src/**/*.c src/*.c) 7 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 8 | 9 | TEST_SRC=$(wildcard tests/*_tests.c) 10 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 11 | 12 | TARGET=build/libstatserve.a 13 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 14 | 15 | # The Target Build 16 | all: $(TARGET) $(SO_TARGET) tests bin/statserve 17 | 18 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 19 | dev: all 20 | 21 | bin/statserve: $(TARGET) 22 | 23 | $(TARGET): CFLAGS += -fPIC 24 | $(TARGET): build $(OBJECTS) 25 | ar rcs $@ $(OBJECTS) 26 | ranlib $@ 27 | 28 | $(SO_TARGET): $(TARGET) $(OBJECTS) 29 | $(CC) -shared -o $@ $(LDFLAGS) $(LIBS) $(OBJECTS) 30 | 31 | build: 32 | @mkdir -p build 33 | @mkdir -p bin 34 | 35 | # The Unit Tests 36 | .PHONY: tests 37 | tests: CFLAGS += $(TARGET) 38 | tests: $(TESTS) 39 | sh ./tests/runtests.sh 40 | 41 | # The Cleaner 42 | clean: 43 | rm -rf build $(OBJECTS) $(TESTS) 44 | rm -f tests/tests.log 45 | find . -name "*.gc*" -exec rm {} \; 46 | rm -rf `find . -name "*.dSYM" -print` 47 | 48 | # The Install 49 | install: all 50 | install -d $(DESTDIR)/$(PREFIX)/lib/ 51 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 52 | 53 | # The Checker 54 | check: 55 | @echo Files with potentially dangerous functions. 56 | @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ 57 | |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true 58 | 59 | -------------------------------------------------------------------------------- /ex50b/statserve/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex50b/statserve/README.md -------------------------------------------------------------------------------- /ex50b/statserve/bin/statserve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "statserve.h" 4 | #include "net.h" 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | check(argc == 3, "USAGE: statserve host port"); 10 | 11 | const char *host = argv[1]; 12 | const char *port = argv[2]; 13 | 14 | check(echo_server(host, port), "Failed to run the echo server."); 15 | 16 | return 0; 17 | 18 | error: 19 | 20 | return 1; 21 | } 22 | -------------------------------------------------------------------------------- /ex50b/statserve/src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex50b/statserve/src/net.h: -------------------------------------------------------------------------------- 1 | #ifndef _net_h 2 | #define _net_h 3 | 4 | #include 5 | 6 | #define BACKLOG 10 7 | 8 | int nonblock(int fd); 9 | int client_connect(char *host, char *port); 10 | int read_some(RingBuffer * buffer, int fd, int is_socket); 11 | int write_some(RingBuffer * buffer, int fd, int is_socket); 12 | int server_listen(const char *host, const char *port); 13 | bstring read_line(RingBuffer *input, const char line_ending); 14 | void send_reply(RingBuffer *send_rb, bstring reply); 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /ex50b/statserve/src/statserve.h: -------------------------------------------------------------------------------- 1 | #ifndef _statserve_h 2 | #define _statserve_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct Command; 9 | 10 | typedef int (*handler_cb)(struct Command *cmd, RingBuffer *send_rb, bstring path); 11 | 12 | typedef struct Command { 13 | bstring command; 14 | bstring name; 15 | struct bstrList *path; 16 | bstring number; 17 | handler_cb handler; 18 | } Command; 19 | 20 | 21 | typedef struct Record { 22 | bstring name; 23 | Stats *stat; 24 | } Record; 25 | 26 | struct tagbstring OK; 27 | 28 | int setup_data_store(); 29 | 30 | struct bstrList *parse_name(bstring name); 31 | 32 | int scan_paths(Command *cmd, RingBuffer *send_rb); 33 | 34 | int parse_line(bstring data, RingBuffer *send_rb); 35 | 36 | int echo_server(const char *host, const char *port); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /ex50b/statserve/tests/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) {\ 12 | log_err(message); return message; } 13 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 14 | message = test(); tests_run++; if (message) return message; 15 | 16 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 17 | argc = 1; \ 18 | debug("----- RUNNING: %s", argv[0]);\ 19 | printf("----\nRUNNING: %s\n", argv[0]);\ 20 | char *result = name();\ 21 | if (result != 0) {\ 22 | printf("FAILED: %s\n", result);\ 23 | }\ 24 | else {\ 25 | printf("ALL TESTS PASSED\n");\ 26 | }\ 27 | printf("Tests run: %d\n", tests_run);\ 28 | exit(result != 0);\ 29 | } 30 | 31 | int tests_run; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex50b/statserve/tests/runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in tests/*_tests 4 | do 5 | if test -f $i 6 | then 7 | if $VALGRIND ./$i 2>> tests/tests.log 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i: here's tests/tests.log" 12 | echo "------" 13 | tail tests/tests.log 14 | exit 1 15 | fi 16 | fi 17 | done 18 | 19 | echo "" 20 | -------------------------------------------------------------------------------- /ex51a/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex51a/README.me -------------------------------------------------------------------------------- /ex51a/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 51 5 | ---- 6 | 7 | Storing the Statistics 8 | 9 | Project Description 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | Learn to store the statistics to the hard disk. 18 | 19 | There are meany issues with this. 20 | 21 | 22 | 23 | The Purpose 24 | ==== 25 | 26 | To teach you about various problems related to securely storing files. 27 | 28 | 29 | 30 | The Requirements 31 | ==== 32 | 33 | For this exercise, you'll add two commands for storing to and loading statistics 34 | from a hard drive: 35 | 36 | store 37 | If there's a URL, store it to a hard drive. 38 | 39 | load 40 | If there are two URLs, load the statistic from the hard drive based on the first URL, and then put it into the second URL that's in memory. 41 | 42 | 43 | 44 | The Requirements 45 | ==== 46 | 47 | 1. If URLs have ``/`` characters in them, then that conflicts with the filesystem's use of slashes. How will you solve this? 48 | 2. If URLs have ``/`` characters in them, then someone can use your server to overwrite files on a hard drive by giving paths to them. How will you solve this? 49 | 3. If you choose to use deeply nested directories, then traversing directories to find files will be very slow. What will you do here? 50 | 51 | 52 | 53 | The Requirements 54 | ==== 55 | 56 | 4. If you choose to use one directory and hash URLs (oops, I gave a hint), then directories with too many files in them are slow. How will you solve this? 57 | 5. What happens when someone loads a statistic from a hard drive into a URL that already exists? 58 | 6. How will someone running ``statserve`` know where the storage should be? 59 | 60 | 61 | 62 | The Clues 63 | ==== 64 | 65 | There are no clues. You can do this. 66 | 67 | 68 | 69 | End Of Lecture 51a 70 | ===== 71 | 72 | 73 | -------------------------------------------------------------------------------- /ex51b/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex51b/README.me -------------------------------------------------------------------------------- /ex51b/statserve/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dSYM 3 | *.so 4 | .*.sw* 5 | *.log 6 | build/* 7 | tests/*_tests 8 | bin/statserve 9 | tags 10 | -------------------------------------------------------------------------------- /ex51b/statserve/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex51b/statserve/LICENSE -------------------------------------------------------------------------------- /ex51b/statserve/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -O2 -Wall -Wextra -I/usr/local/include -Isrc -rdynamic $(OPTFLAGS) 2 | LIBS=-llcthw $(OPTLIBS) 3 | LDFLAGS=-L/usr/local/lib $(LIBS) 4 | PREFIX?=/usr/local 5 | 6 | SOURCES=$(wildcard src/**/*.c src/*.c) 7 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 8 | 9 | TEST_SRC=$(wildcard tests/*_tests.c) 10 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 11 | 12 | TARGET=build/libstatserve.a 13 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 14 | 15 | # The Target Build 16 | all: $(TARGET) $(SO_TARGET) tests bin/statserve 17 | 18 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 19 | dev: all 20 | 21 | bin/statserve: $(TARGET) 22 | 23 | $(TARGET): CFLAGS += -fPIC 24 | $(TARGET): build $(OBJECTS) 25 | ar rcs $@ $(OBJECTS) 26 | ranlib $@ 27 | 28 | $(SO_TARGET): $(TARGET) $(OBJECTS) 29 | $(CC) -shared -o $@ $(LDFLAGS) $(LIBS) $(OBJECTS) 30 | 31 | $(TESTS): $(TARGET) $(SO_TARGET) 32 | 33 | build: 34 | @mkdir -p build 35 | @mkdir -p bin 36 | 37 | # The Unit Tests 38 | .PHONY: tests 39 | tests: CFLAGS += $(TARGET) 40 | tests: $(TESTS) 41 | sh ./tests/runtests.sh 42 | 43 | # The Cleaner 44 | clean: 45 | rm -rf build $(OBJECTS) $(TESTS) 46 | rm -f tests/tests.log 47 | find . -name "*.gc*" -exec rm {} \; 48 | rm -rf `find . -name "*.dSYM" -print` 49 | 50 | # The Install 51 | install: all 52 | install -d $(DESTDIR)/$(PREFIX)/lib/ 53 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 54 | 55 | # The Checker 56 | check: 57 | @echo Files with potentially dangerous functions. 58 | @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ 59 | |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true 60 | 61 | -------------------------------------------------------------------------------- /ex51b/statserve/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex51b/statserve/README.md -------------------------------------------------------------------------------- /ex51b/statserve/bin/statserve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "statserve.h" 4 | #include "net.h" 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | check(argc == 4, "USAGE: statserve host port store_path"); 10 | 11 | const char *host = argv[1]; 12 | const char *port = argv[2]; 13 | const char *store_path = argv[3]; 14 | 15 | check(run_server(host, port, store_path), "Failed to run the echo server."); 16 | 17 | return 0; 18 | 19 | error: 20 | 21 | return 1; 22 | } 23 | -------------------------------------------------------------------------------- /ex51b/statserve/src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\ 12 | __FILE__, __LINE__, ##__VA_ARGS__) 13 | #endif 14 | 15 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 16 | 17 | #define log_err(M, ...) fprintf(stderr,\ 18 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\ 19 | clean_errno(), ##__VA_ARGS__) 20 | 21 | #define log_warn(M, ...) fprintf(stderr,\ 22 | "[WARN] (%s:%d: errno: %s) " M "\n",\ 23 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 24 | 25 | #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ 26 | __FILE__, __LINE__, ##__VA_ARGS__) 27 | 28 | #define check(A, M, ...) if(!(A)) {\ 29 | log_err(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ 32 | errno=0; goto error; } 33 | 34 | #define check_mem(A) check((A), "Out of memory.") 35 | 36 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ 37 | errno=0; goto error; } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /ex51b/statserve/src/net.h: -------------------------------------------------------------------------------- 1 | #ifndef _net_h 2 | #define _net_h 3 | 4 | #include 5 | 6 | #define BACKLOG 10 7 | 8 | int nonblock(int fd); 9 | int client_connect(char *host, char *port); 10 | int read_some(RingBuffer * buffer, int fd, int is_socket); 11 | int write_some(RingBuffer * buffer, int fd, int is_socket); 12 | int server_listen(const char *host, const char *port); 13 | bstring read_line(RingBuffer *input, const char line_ending); 14 | void send_reply(RingBuffer *send_rb, bstring reply); 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /ex51b/statserve/src/statserve.h: -------------------------------------------------------------------------------- 1 | #ifndef _statserve_h 2 | #define _statserve_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct Command; 9 | 10 | typedef int (*handler_cb)(struct Command *cmd, RingBuffer *send_rb, bstring path); 11 | 12 | typedef struct Command { 13 | bstring command; 14 | bstring name; 15 | struct bstrList *path; 16 | bstring number; 17 | bstring arg; 18 | handler_cb handler; 19 | } Command; 20 | 21 | 22 | typedef struct Record { 23 | bstring name; 24 | Stats *stat; 25 | } Record; 26 | 27 | struct tagbstring OK; 28 | 29 | int setup_data_store(const char *store_path); 30 | 31 | struct bstrList *parse_name(bstring name); 32 | 33 | int scan_paths(Command *cmd, RingBuffer *send_rb); 34 | 35 | int parse_line(bstring data, RingBuffer *send_rb); 36 | 37 | int run_server(const char *host, const char *port, const char *store_path); 38 | 39 | bstring sanitize_location(bstring base, bstring path); 40 | 41 | bstring encrypt_armor_name(bstring name); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /ex51b/statserve/tests/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) {\ 12 | log_err(message); return message; } 13 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 14 | message = test(); tests_run++; if (message) return message; 15 | 16 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 17 | argc = 1; \ 18 | debug("----- RUNNING: %s", argv[0]);\ 19 | printf("----\nRUNNING: %s\n", argv[0]);\ 20 | char *result = name();\ 21 | if (result != 0) {\ 22 | printf("FAILED: %s\n", result);\ 23 | }\ 24 | else {\ 25 | printf("ALL TESTS PASSED\n");\ 26 | }\ 27 | printf("Tests run: %d\n", tests_run);\ 28 | exit(result != 0);\ 29 | } 30 | 31 | int tests_run; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ex51b/statserve/tests/runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in tests/*_tests 4 | do 5 | if test -f $i 6 | then 7 | if $VALGRIND ./$i 2>> tests/tests.log 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i: here's tests/tests.log" 12 | echo "------" 13 | tail tests/tests.log 14 | exit 1 15 | fi 16 | fi 17 | done 18 | 19 | echo "" 20 | -------------------------------------------------------------------------------- /ex52a/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex52a/README.me -------------------------------------------------------------------------------- /ex52a/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 52a 5 | ---- 6 | 7 | Hacking and Improving Your Server: 8 | 9 | Project Description 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | Learn to improve your server by hacking it. 18 | 19 | 20 | 21 | The Purpose 22 | ==== 23 | 24 | Turn on defensive mode and destroy what you've created to make it better. 25 | 26 | 27 | 28 | My Protocol Is Junk 29 | ==== 30 | 31 | The protocol should have specified sizes of elements, 32 | or a correctly written parser using a parser generator. 33 | 34 | 35 | 36 | Hacking The Protocol 37 | ==== 38 | 39 | * Fuzzing the names. 40 | * Thrashing the size of strings. 41 | * Putting '\0' in the data. 42 | * Feeding crazy large numbers in. 43 | 44 | 45 | 46 | The Rule 47 | ==== 48 | 49 | Protocols without exact grammars *or* fixed size elements will be hacked. 50 | 51 | 52 | 53 | My Disk Storage Is Junk 54 | ==== 55 | 56 | "What?! C'mon!" 57 | 58 | 59 | 60 | Hacking Your Disk 61 | ==== 62 | 63 | * Fuzzing the file names. 64 | * Filling the disk. 65 | * Rampant create/delete operations. 66 | * Doing insanely long directories. 67 | * Trying to access arbitrary files. 68 | 69 | 70 | 71 | The Rule 72 | ==== 73 | 74 | The disk works, but you need a way to monitor storage or just have 75 | tons of it. 76 | 77 | Watch for arbitrary paths and *always* sanitize them. 78 | 79 | 80 | 81 | First Code Review 82 | ==== 83 | 84 | I'll now do a "first pass" code review. 85 | 86 | I just go through quick, looking for bugs and drop BUG: comments. 87 | 88 | 89 | 90 | 91 | End of Lecture 52a 92 | ===== 93 | 94 | 95 | -------------------------------------------------------------------------------- /ex52b/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex52b/README.me -------------------------------------------------------------------------------- /ex52b/hacker.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | import random 4 | 5 | randin = open("/dev/urandom", "r") 6 | 7 | while True: 8 | for i in range(0, 2048): 9 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 | 11 | server_address = ('localhost', 10000) 12 | print 'connecting to %s port %s' % server_address 13 | sock.connect(server_address) 14 | 15 | try: 16 | name = randin.read(i) 17 | number = "%s" % random.getrandbits(64) 18 | 19 | sock.sendall('create /%s %s\n' % (name, number)) 20 | data = sock.recv(3) 21 | print 'received "%s"' % data 22 | 23 | sock.sendall('store /%s\n' % name) 24 | data = sock.recv(3) 25 | print 'received "%s"' % data 26 | except socket.error: 27 | pass 28 | 29 | finally: 30 | print 'closing socket' 31 | sock.close() 32 | -------------------------------------------------------------------------------- /ex52b/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 52b 5 | ---- 6 | 7 | Hacking and Improving Your Server 8 | 9 | Solution 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | A more formal code review to demonstrate how I think 18 | about my own code. 19 | 20 | 21 | 22 | The Purpose 23 | ==== 24 | 25 | Teach you that you *never* assume your code is good. 26 | 27 | You're a scientist not a god. 28 | 29 | Always assume there's a chance you're wrong. 30 | 31 | 32 | 33 | Code Review Of Protocol Handling 34 | ==== 35 | 36 | A quick code review of the protocol handling then simple hacking. 37 | 38 | 39 | 40 | 41 | Hacking Demo 42 | ==== 43 | 44 | This is an ultra light hacking demo. 45 | 46 | I could do much worse if I had more time. 47 | 48 | 49 | 50 | Fixing These Flaws 51 | ==== 52 | 53 | * Add rate limiting calculations with stat.h 54 | * Add limits on name lengths. 55 | * Change to a md5 or sha1 hash, the encipher thing is dumb. 56 | * Forking kind of saves us ironically, but it has to go. 57 | 58 | Look at the github repository to see all of the things I fixed. 59 | 60 | 61 | 62 | 63 | End of Lecture 52b 64 | ===== 65 | 66 | 67 | -------------------------------------------------------------------------------- /ex52c/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex52c/README.me -------------------------------------------------------------------------------- /ex52c/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 52c 5 | ---- 6 | 7 | Hacking and Improving Your Server 8 | 9 | Solution 10 | ---- 11 | 12 | 13 | 14 | The Plan 15 | ==== 16 | 17 | Discuss the final things I'd do to make a project complete, by showing you 18 | my final project as it lives on github. 19 | 20 | 21 | 22 | Getting It Online 23 | ==== 24 | 25 | Get it online and accessible to people. 26 | 27 | 28 | 29 | Documenting It 30 | ==== 31 | 32 | Document it and improve the usability to make sure that the documents are easy to read. 33 | 34 | 35 | 36 | Test Coverage 37 | ==== 38 | 39 | Do as much test coverage as possible. 40 | 41 | 42 | 43 | Handling Corner Cases 44 | ==== 45 | 46 | Improve any corner cases and add defenses against any attacks that I can find. 47 | 48 | 49 | 50 | Do More Code Reviews 51 | ==== 52 | 53 | 54 | 55 | Have Fun 56 | ==== 57 | 58 | 59 | 60 | End of Lecture 52c 61 | ===== 62 | 63 | 64 | -------------------------------------------------------------------------------- /ex6/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex6/README.me -------------------------------------------------------------------------------- /ex6/ex6.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex6/ex6.c -------------------------------------------------------------------------------- /ex7/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex7/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex7/README.me -------------------------------------------------------------------------------- /ex7/ex7.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int distance = 100; 6 | float power = 2.345f; 7 | double super_power = 56789.4532; 8 | char initial = 'A'; 9 | char first_name[] = "Zed"; 10 | char last_name[] = "Shaw"; 11 | 12 | first_name[3] = 'Z'; 13 | 14 | printf("You are %d miles away.\n", distance); 15 | printf("You have %f levels of power.\n", power); 16 | printf("You have %f awesome super powers.\n", super_power); 17 | printf("I have an initial %c.\n", initial); 18 | printf("I have a first name %s.\n", first_name); 19 | printf("I have a last name %s.\n", last_name); 20 | printf("My whole name is %s %c. %s.\n", 21 | first_name, initial, last_name); 22 | 23 | int bugs = 100; 24 | double bug_rate = 1.2; 25 | 26 | printf("You have %d bugs at the imaginary rate of %f.\n", 27 | bugs, bug_rate); 28 | 29 | long universe_of_defects = 1L * 1024L * 1024L * 1024L; 30 | printf("The entire universe has %ld bugs.\n", universe_of_defects); 31 | 32 | double expected_bugs = bugs * bug_rate; 33 | printf("You are expected to have %f bugs.\n", expected_bugs); 34 | 35 | double part_of_universe = expected_bugs / universe_of_defects; 36 | printf("That is only a %e portion of the universe.\n", 37 | part_of_universe); 38 | 39 | // this makes no sense, just a demo of something weird 40 | char nul_byte = '\0'; 41 | int care_percentage = bugs * nul_byte; 42 | printf("Which means you should care %d%%.\n", care_percentage); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /ex7/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 7 5 | ---- 6 | 7 | Variables and Types 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | * Learn some basic variables and types. 15 | * int, float, double, char, and strings. 16 | 17 | 18 | 19 | The Code 20 | ==== 21 | 22 | 23 | 24 | The Analysis 25 | ==== 26 | 27 | 28 | 29 | Breaking It 30 | ==== 31 | 32 | * Strings give us so much more fun now! 33 | * Crafting bad strings. 34 | * Messing with pointers. 35 | * Abusing printf. 36 | 37 | 38 | 39 | Extra Credit 40 | ==== 41 | 42 | * Make the number you assign to *universe_of_defects* various 43 | sizes until you get a warning from the compiler. 44 | * What do these really huge numbers actually print out? 45 | * Change *long* to *unsigned long* and try to find 46 | the number that makes it too big. 47 | * Go search online to find out what *unsigned* does. 48 | * Try to explain to yourself (before I do in the next exercise) 49 | why you can multiply a *char* and an *int*. 50 | 51 | 52 | 53 | End Of Lecture 7 54 | ===== 55 | 56 | 57 | -------------------------------------------------------------------------------- /ex8/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex8/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex8/README.me -------------------------------------------------------------------------------- /ex8/ex8.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int i = 0; 6 | 7 | if (argc == 1) { 8 | printf("You only have one argument. You suck.\n"); 9 | } else if (argc > 1 && argc < 4) { 10 | printf("Here's your arguments:\n"); 11 | 12 | for (i = 0; i < argc; i++) { 13 | printf("%s ", argv[i]); 14 | } 15 | printf("\n"); 16 | } else if (argc > 10) { 17 | printf("You have too many arguments. You suck.\n"); 18 | } 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /ex8/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 8 5 | ---- 6 | 7 | If, Else-If, Else 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | Simply learn to use this: 15 | 16 | if(TEST) { 17 | CODE; 18 | } else if(TEST) { 19 | CODE; 20 | } else { 21 | CODE; 22 | } 23 | 24 | 25 | 26 | The Code 27 | ==== 28 | 29 | 30 | 31 | The Analysis 32 | ==== 33 | 34 | 35 | 36 | Breaking It 37 | ==== 38 | 39 | * It kind of just works, but remove the *else* and change the logic. 40 | 41 | 42 | 43 | Extra Credit 44 | ==== 45 | 46 | * You were briefly introduced to *&&*, which does an *and* comparison, 47 | so go research online the different *Boolean operators*. 48 | * Write a few more test cases for this program to see what you can come 49 | up with. 50 | 51 | 52 | 53 | End Of Lecture 8 54 | ===== 55 | 56 | -------------------------------------------------------------------------------- /ex9/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | 3 | -------------------------------------------------------------------------------- /ex9/README.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/ex9/README.me -------------------------------------------------------------------------------- /ex9/ex9.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int i; 6 | while (i < 25) { 7 | printf("%d\n", i); 8 | i++; 9 | } 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ex9/lecture.md: -------------------------------------------------------------------------------- 1 | Learn C The Hard Way 2 | ======= 3 | 4 | Exercise 9 5 | ---- 6 | 7 | While-Loop and Boolean Expressions 8 | 9 | 10 | 11 | The Plan 12 | ==== 13 | 14 | You first loop shall be the *while*: 15 | 16 | while(TEST) { 17 | CODE; 18 | } 19 | 20 | 21 | 22 | The Code 23 | ==== 24 | 25 | 26 | 27 | The Analysis 28 | ==== 29 | 30 | 31 | 32 | 33 | Breaking It 34 | ==== 35 | 36 | * Forget to initialize the *int i*. 37 | * Forget to do an i++ and make it run forever. 38 | 39 | 40 | 41 | Extra Credit 42 | ==== 43 | 44 | * Make the loop count backward by using ``i--`` to start 45 | at 25 and go to 0. 46 | * Write a few more complex ``while-loops`` using what you know 47 | so far. 48 | 49 | 50 | 51 | End Of Lecture 9 52 | ===== 53 | 54 | 55 | -------------------------------------------------------------------------------- /next/lecture.md: -------------------------------------------------------------------------------- 1 | 2 | Learn C The Hard Way 3 | ======= 4 | 5 | Next Steps 6 | ---- 7 | 8 | Goodbye Friendly Friends 9 | 10 | 11 | 12 | The Plan 13 | ==== 14 | 15 | Some parting words on your new journey. 16 | 17 | 18 | 19 | The Purpose 20 | ==== 21 | 22 | Advice for the future. 23 | 24 | 25 | 26 | Read More Books On C 27 | ==== 28 | 29 | 30 | 31 | Don't Make More C Code 32 | ==== 33 | 34 | 35 | 36 | Learn 4 More Programming Languages 37 | ==== 38 | 39 | 40 | 41 | Study Algorithms For Real 42 | ==== 43 | 44 | 45 | 46 | Don't Take This Too Seriously 47 | ==== 48 | 49 | 50 | 51 | Arrogant Programmers Are Terrible Programmers 52 | ==== 53 | 54 | 55 | 56 | Learn To Paint 57 | ==== 58 | 59 | 60 | 61 | End of Learn C The Hard Way 62 | ===== 63 | 64 | Email help@learncodethehardway.org or ask @lzsthw on Twitter. 65 | 66 | -------------------------------------------------------------------------------- /static/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 Hakim El Hattab, http://hakim.se 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /static/css/theme/README.md: -------------------------------------------------------------------------------- 1 | ## Dependencies 2 | 3 | Themes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment including the Grunt dependencies installed before proceding: https://github.com/hakimel/reveal.js#full-setup 4 | 5 | ## Creating a Theme 6 | 7 | To create your own theme, start by duplicating any ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source) and adding it to the compilation list in the [Gruntfile](https://github.com/hakimel/reveal.js/blob/master/Gruntfile.js). 8 | 9 | Each theme file does four things in the following order: 10 | 11 | 1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)** 12 | Shared utility functions. 13 | 14 | 2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)** 15 | Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3. 16 | 17 | 3. **Override** 18 | This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding any selectors and styles you please. 19 | 20 | 4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)** 21 | The template theme file which will generate final CSS output based on the currently defined variables. 22 | 23 | When you are done, run `grunt css-themes` to compile the Sass file to CSS and you are ready to use your new theme. 24 | -------------------------------------------------------------------------------- /static/css/theme/source/beige.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Beige theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @import url(../../lib/font/league-gothic/league-gothic.css); 17 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 18 | 19 | 20 | // Override theme settings (see ../template/settings.scss) 21 | $mainColor: #333; 22 | $headingColor: #333; 23 | $headingTextShadow: none; 24 | $backgroundColor: #f7f3de; 25 | $linkColor: #8b743d; 26 | $linkColorHover: lighten( $linkColor, 20% ); 27 | $selectionBackgroundColor: rgba(79, 64, 28, 0.99); 28 | $heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); 29 | 30 | // Background generator 31 | @mixin bodyBackground() { 32 | @include radial-gradient( rgba(247,242,211,1), rgba(255,255,255,1) ); 33 | } 34 | 35 | 36 | 37 | // Theme template ------------------------------ 38 | @import "../template/theme"; 39 | // --------------------------------------------- -------------------------------------------------------------------------------- /static/css/theme/source/black.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Black theme for reveal.js. This is the opposite of the 'white' theme. 3 | * 4 | * Copyright (C) 2015 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/source-sans-pro/source-sans-pro.css); 16 | 17 | 18 | // Override theme settings (see ../template/settings.scss) 19 | $backgroundColor: #222; 20 | 21 | $mainColor: #fff; 22 | $headingColor: #fff; 23 | 24 | $mainFontSize: 38px; 25 | $mainFont: 'Source Sans Pro', Helvetica, sans-serif; 26 | $headingFont: 'Source Sans Pro', Helvetica, sans-serif; 27 | $headingTextShadow: none; 28 | $headingLetterSpacing: normal; 29 | $headingTextTransform: uppercase; 30 | $headingFontWeight: 600; 31 | $linkColor: #42affa; 32 | $linkColorHover: lighten( $linkColor, 15% ); 33 | $selectionBackgroundColor: lighten( $linkColor, 25% ); 34 | 35 | $heading1Size: 2.5em; 36 | $heading2Size: 1.6em; 37 | $heading3Size: 1.3em; 38 | $heading4Size: 1.0em; 39 | 40 | section.has-light-background { 41 | &, h1, h2, h3, h4, h5, h6 { 42 | color: #222; 43 | } 44 | } 45 | 46 | 47 | // Theme template ------------------------------ 48 | @import "../template/theme"; 49 | // --------------------------------------------- -------------------------------------------------------------------------------- /static/css/theme/source/league.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * League theme for reveal.js. 3 | * 4 | * This was the default theme pre-3.0.0. 5 | * 6 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | 10 | // Default mixins and settings ----------------- 11 | @import "../template/mixins"; 12 | @import "../template/settings"; 13 | // --------------------------------------------- 14 | 15 | 16 | 17 | // Include theme-specific fonts 18 | @import url(../../lib/font/league-gothic/league-gothic.css); 19 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 20 | 21 | // Override theme settings (see ../template/settings.scss) 22 | $headingTextShadow: 0px 0px 6px rgba(0,0,0,0.2); 23 | $heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); 24 | 25 | // Background generator 26 | @mixin bodyBackground() { 27 | @include radial-gradient( rgba(28,30,32,1), rgba(85,90,95,1) ); 28 | } 29 | 30 | 31 | 32 | // Theme template ------------------------------ 33 | @import "../template/theme"; 34 | // --------------------------------------------- -------------------------------------------------------------------------------- /static/css/theme/source/moon.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Dark theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/league-gothic/league-gothic.css); 16 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 17 | 18 | /** 19 | * Solarized colors by Ethan Schoonover 20 | */ 21 | html * { 22 | color-profile: sRGB; 23 | rendering-intent: auto; 24 | } 25 | 26 | // Solarized colors 27 | $base03: #002b36; 28 | $base02: #073642; 29 | $base01: #586e75; 30 | $base00: #657b83; 31 | $base0: #839496; 32 | $base1: #93a1a1; 33 | $base2: #eee8d5; 34 | $base3: #fdf6e3; 35 | $yellow: #b58900; 36 | $orange: #cb4b16; 37 | $red: #dc322f; 38 | $magenta: #d33682; 39 | $violet: #6c71c4; 40 | $blue: #268bd2; 41 | $cyan: #2aa198; 42 | $green: #859900; 43 | 44 | // Override theme settings (see ../template/settings.scss) 45 | $mainColor: $base1; 46 | $headingColor: $base2; 47 | $headingTextShadow: none; 48 | $backgroundColor: $base03; 49 | $linkColor: $blue; 50 | $linkColorHover: lighten( $linkColor, 20% ); 51 | $selectionBackgroundColor: $magenta; 52 | 53 | 54 | 55 | // Theme template ------------------------------ 56 | @import "../template/theme"; 57 | // --------------------------------------------- 58 | -------------------------------------------------------------------------------- /static/css/theme/source/night.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Black theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(https://fonts.googleapis.com/css?family=Montserrat:700); 16 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); 17 | 18 | 19 | // Override theme settings (see ../template/settings.scss) 20 | $backgroundColor: #111; 21 | 22 | $mainFont: 'Open Sans', sans-serif; 23 | $linkColor: #e7ad52; 24 | $linkColorHover: lighten( $linkColor, 20% ); 25 | $headingFont: 'Montserrat', Impact, sans-serif; 26 | $headingTextShadow: none; 27 | $headingLetterSpacing: -0.03em; 28 | $headingTextTransform: none; 29 | $selectionBackgroundColor: #e7ad52; 30 | $mainFontSize: 30px; 31 | 32 | 33 | // Theme template ------------------------------ 34 | @import "../template/theme"; 35 | // --------------------------------------------- -------------------------------------------------------------------------------- /static/css/theme/source/serif.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is brown. 4 | * 5 | * This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed. 6 | */ 7 | 8 | 9 | // Default mixins and settings ----------------- 10 | @import "../template/mixins"; 11 | @import "../template/settings"; 12 | // --------------------------------------------- 13 | 14 | 15 | 16 | // Override theme settings (see ../template/settings.scss) 17 | $mainFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 18 | $mainColor: #000; 19 | $headingFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 20 | $headingColor: #383D3D; 21 | $headingTextShadow: none; 22 | $headingTextTransform: none; 23 | $backgroundColor: #F0F1EB; 24 | $linkColor: #51483D; 25 | $linkColorHover: lighten( $linkColor, 20% ); 26 | $selectionBackgroundColor: #26351C; 27 | 28 | .reveal a { 29 | line-height: 1.3em; 30 | } 31 | 32 | 33 | // Theme template ------------------------------ 34 | @import "../template/theme"; 35 | // --------------------------------------------- 36 | -------------------------------------------------------------------------------- /static/css/theme/source/simple.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * A simple theme for reveal.js presentations, similar 3 | * to the default theme. The accent color is darkblue. 4 | * 5 | * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. 6 | * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 7 | */ 8 | 9 | 10 | // Default mixins and settings ----------------- 11 | @import "../template/mixins"; 12 | @import "../template/settings"; 13 | // --------------------------------------------- 14 | 15 | 16 | 17 | // Include theme-specific fonts 18 | @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); 19 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 20 | 21 | 22 | // Override theme settings (see ../template/settings.scss) 23 | $mainFont: 'Lato', sans-serif; 24 | $mainColor: #000; 25 | $headingFont: 'News Cycle', Impact, sans-serif; 26 | $headingColor: #000; 27 | $headingTextShadow: none; 28 | $headingTextTransform: none; 29 | $backgroundColor: #fff; 30 | $linkColor: #00008B; 31 | $linkColorHover: lighten( $linkColor, 20% ); 32 | $selectionBackgroundColor: rgba(0, 0, 0, 0.99); 33 | 34 | 35 | 36 | // Theme template ------------------------------ 37 | @import "../template/theme"; 38 | // --------------------------------------------- -------------------------------------------------------------------------------- /static/css/theme/source/sky.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Sky theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | 15 | // Include theme-specific fonts 16 | @import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic); 17 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); 18 | 19 | 20 | // Override theme settings (see ../template/settings.scss) 21 | $mainFont: 'Open Sans', sans-serif; 22 | $mainColor: #333; 23 | $headingFont: 'Quicksand', sans-serif; 24 | $headingColor: #333; 25 | $headingLetterSpacing: -0.08em; 26 | $headingTextShadow: none; 27 | $backgroundColor: #f7fbfc; 28 | $linkColor: #3b759e; 29 | $linkColorHover: lighten( $linkColor, 20% ); 30 | $selectionBackgroundColor: #134674; 31 | 32 | // Fix links so they are not cut off 33 | .reveal a { 34 | line-height: 1.3em; 35 | } 36 | 37 | // Background generator 38 | @mixin bodyBackground() { 39 | @include radial-gradient( #add9e4, #f7fbfc ); 40 | } 41 | 42 | 43 | 44 | // Theme template ------------------------------ 45 | @import "../template/theme"; 46 | // --------------------------------------------- 47 | -------------------------------------------------------------------------------- /static/css/theme/source/solarized.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Solarized Light theme for reveal.js. 3 | * Author: Achim Staebler 4 | */ 5 | 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../template/mixins"; 9 | @import "../template/settings"; 10 | // --------------------------------------------- 11 | 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/league-gothic/league-gothic.css); 16 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 17 | 18 | 19 | /** 20 | * Solarized colors by Ethan Schoonover 21 | */ 22 | html * { 23 | color-profile: sRGB; 24 | rendering-intent: auto; 25 | } 26 | 27 | // Solarized colors 28 | $base03: #002b36; 29 | $base02: #073642; 30 | $base01: #586e75; 31 | $base00: #657b83; 32 | $base0: #839496; 33 | $base1: #93a1a1; 34 | $base2: #eee8d5; 35 | $base3: #fdf6e3; 36 | $yellow: #b58900; 37 | $orange: #cb4b16; 38 | $red: #dc322f; 39 | $magenta: #d33682; 40 | $violet: #6c71c4; 41 | $blue: #268bd2; 42 | $cyan: #2aa198; 43 | $green: #859900; 44 | 45 | // Override theme settings (see ../template/settings.scss) 46 | $mainColor: $base00; 47 | $headingColor: $base01; 48 | $headingTextShadow: none; 49 | $backgroundColor: $base3; 50 | $linkColor: $blue; 51 | $linkColorHover: lighten( $linkColor, 20% ); 52 | $selectionBackgroundColor: $magenta; 53 | 54 | // Background generator 55 | // @mixin bodyBackground() { 56 | // @include radial-gradient( rgba($base3,1), rgba(lighten($base3, 20%),1) ); 57 | // } 58 | 59 | 60 | 61 | // Theme template ------------------------------ 62 | @import "../template/theme"; 63 | // --------------------------------------------- 64 | -------------------------------------------------------------------------------- /static/css/theme/source/white.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * White theme for reveal.js. This is the opposite of the 'black' theme. 3 | * 4 | * Copyright (C) 2015 Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | 8 | // Default mixins and settings ----------------- 9 | @import "../template/mixins"; 10 | @import "../template/settings"; 11 | // --------------------------------------------- 12 | 13 | 14 | // Include theme-specific fonts 15 | @import url(../../lib/font/source-sans-pro/source-sans-pro.css); 16 | 17 | 18 | // Override theme settings (see ../template/settings.scss) 19 | $backgroundColor: #fff; 20 | 21 | $mainColor: #222; 22 | $headingColor: #222; 23 | 24 | $mainFontSize: 38px; 25 | $mainFont: 'Source Sans Pro', Helvetica, sans-serif; 26 | $headingFont: 'Source Sans Pro', Helvetica, sans-serif; 27 | $headingTextShadow: none; 28 | $headingLetterSpacing: normal; 29 | $headingTextTransform: uppercase; 30 | $headingFontWeight: 600; 31 | $linkColor: #2a76dd; 32 | $linkColorHover: lighten( $linkColor, 15% ); 33 | $selectionBackgroundColor: lighten( $linkColor, 25% ); 34 | 35 | $heading1Size: 2.5em; 36 | $heading2Size: 1.6em; 37 | $heading3Size: 1.3em; 38 | $heading4Size: 1.0em; 39 | 40 | section.has-dark-background { 41 | &, h1, h2, h3, h4, h5, h6 { 42 | color: #fff; 43 | } 44 | } 45 | 46 | 47 | // Theme template ------------------------------ 48 | @import "../template/theme"; 49 | // --------------------------------------------- -------------------------------------------------------------------------------- /static/css/theme/template/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin vertical-gradient( $top, $bottom ) { 2 | background: $top; 3 | background: -moz-linear-gradient( top, $top 0%, $bottom 100% ); 4 | background: -webkit-gradient( linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom) ); 5 | background: -webkit-linear-gradient( top, $top 0%, $bottom 100% ); 6 | background: -o-linear-gradient( top, $top 0%, $bottom 100% ); 7 | background: -ms-linear-gradient( top, $top 0%, $bottom 100% ); 8 | background: linear-gradient( top, $top 0%, $bottom 100% ); 9 | } 10 | 11 | @mixin horizontal-gradient( $top, $bottom ) { 12 | background: $top; 13 | background: -moz-linear-gradient( left, $top 0%, $bottom 100% ); 14 | background: -webkit-gradient( linear, left top, right top, color-stop(0%,$top), color-stop(100%,$bottom) ); 15 | background: -webkit-linear-gradient( left, $top 0%, $bottom 100% ); 16 | background: -o-linear-gradient( left, $top 0%, $bottom 100% ); 17 | background: -ms-linear-gradient( left, $top 0%, $bottom 100% ); 18 | background: linear-gradient( left, $top 0%, $bottom 100% ); 19 | } 20 | 21 | @mixin radial-gradient( $outer, $inner, $type: circle ) { 22 | background: $outer; 23 | background: -moz-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 24 | background: -webkit-gradient( radial, center center, 0px, center center, 100%, color-stop(0%,$inner), color-stop(100%,$outer) ); 25 | background: -webkit-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 26 | background: -o-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 27 | background: -ms-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 28 | background: radial-gradient( center, $type cover, $inner 0%, $outer 100% ); 29 | } -------------------------------------------------------------------------------- /static/css/theme/template/settings.scss: -------------------------------------------------------------------------------- 1 | // Base settings for all themes that can optionally be 2 | // overridden by the super-theme 3 | 4 | // Background of the presentation 5 | $backgroundColor: #2b2b2b; 6 | 7 | // Primary/body text 8 | $mainFont: 'Lato', sans-serif; 9 | $mainFontSize: 36px; 10 | $mainColor: #eee; 11 | 12 | // Vertical spacing between blocks of text 13 | $blockMargin: 20px; 14 | 15 | // Headings 16 | $headingMargin: 0 0 $blockMargin 0; 17 | $headingFont: 'League Gothic', Impact, sans-serif; 18 | $headingColor: #eee; 19 | $headingLineHeight: 1.2; 20 | $headingLetterSpacing: normal; 21 | $headingTextTransform: uppercase; 22 | $headingTextShadow: none; 23 | $headingFontWeight: normal; 24 | $heading1TextShadow: $headingTextShadow; 25 | 26 | $heading1Size: 3.77em; 27 | $heading2Size: 2.11em; 28 | $heading3Size: 1.55em; 29 | $heading4Size: 1.00em; 30 | 31 | // Links and actions 32 | $linkColor: #13DAEC; 33 | $linkColorHover: lighten( $linkColor, 20% ); 34 | 35 | // Text selection 36 | $selectionBackgroundColor: #FF5E99; 37 | $selectionColor: #fff; 38 | 39 | // Generates the presentation background, can be overridden 40 | // to return a background image or gradient 41 | @mixin bodyBackground() { 42 | background: $backgroundColor; 43 | } -------------------------------------------------------------------------------- /static/lib/font/league-gothic/LICENSE: -------------------------------------------------------------------------------- 1 | SIL Open Font License (OFL) 2 | http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL 3 | -------------------------------------------------------------------------------- /static/lib/font/league-gothic/league-gothic.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'League Gothic'; 3 | src: url('league-gothic.eot'); 4 | src: url('league-gothic.eot?#iefix') format('embedded-opentype'), 5 | url('league-gothic.woff') format('woff'), 6 | url('league-gothic.ttf') format('truetype'); 7 | 8 | font-weight: normal; 9 | font-style: normal; 10 | } -------------------------------------------------------------------------------- /static/lib/font/league-gothic/league-gothic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/league-gothic/league-gothic.eot -------------------------------------------------------------------------------- /static/lib/font/league-gothic/league-gothic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/league-gothic/league-gothic.ttf -------------------------------------------------------------------------------- /static/lib/font/league-gothic/league-gothic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/league-gothic/league-gothic.woff -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-italic.eot -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-italic.ttf -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-italic.woff -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-regular.eot -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-regular.ttf -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-regular.woff -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-semibold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-semibold.eot -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-semibold.ttf -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-semibold.woff -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedshaw/learn-c-the-hard-way-lectures/45703363ecabc6cdbc32143965adc32b3cae2b2f/static/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff -------------------------------------------------------------------------------- /static/lib/font/source-sans-pro/source-sans-pro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Sans Pro'; 3 | src: url('source-sans-pro-regular.eot'); 4 | src: url('source-sans-pro-regular.eot?#iefix') format('embedded-opentype'), 5 | url('source-sans-pro-regular.woff') format('woff'), 6 | url('source-sans-pro-regular.ttf') format('truetype'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | 11 | @font-face { 12 | font-family: 'Source Sans Pro'; 13 | src: url('source-sans-pro-italic.eot'); 14 | src: url('source-sans-pro-italic.eot?#iefix') format('embedded-opentype'), 15 | url('source-sans-pro-italic.woff') format('woff'), 16 | url('source-sans-pro-italic.ttf') format('truetype'); 17 | font-weight: normal; 18 | font-style: italic; 19 | } 20 | 21 | @font-face { 22 | font-family: 'Source Sans Pro'; 23 | src: url('source-sans-pro-semibold.eot'); 24 | src: url('source-sans-pro-semibold.eot?#iefix') format('embedded-opentype'), 25 | url('source-sans-pro-semibold.woff') format('woff'), 26 | url('source-sans-pro-semibold.ttf') format('truetype'); 27 | font-weight: 600; 28 | font-style: normal; 29 | } 30 | 31 | @font-face { 32 | font-family: 'Source Sans Pro'; 33 | src: url('source-sans-pro-semibolditalic.eot'); 34 | src: url('source-sans-pro-semibolditalic.eot?#iefix') format('embedded-opentype'), 35 | url('source-sans-pro-semibolditalic.woff') format('woff'), 36 | url('source-sans-pro-semibolditalic.ttf') format('truetype'); 37 | font-weight: 600; 38 | font-style: italic; 39 | } -------------------------------------------------------------------------------- /static/lib/js/classList.js: -------------------------------------------------------------------------------- 1 | /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/ 2 | if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(j){var a="classList",f="prototype",m=(j.HTMLElement||j.Element)[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p