diff --git a/chapters/chapter_0.c b/chapters/chapter_0.c index abb0151..d5ad66b 100644 --- a/chapters/chapter_0.c +++ b/chapters/chapter_0.c @@ -220,6 +220,10 @@ char * string_concatenate (char * string_0, char * string_1) { return (result); } +char * string_reverse (char * string) { // Example of implementing "unlimited" version by calling "limited" version. + return (string_reverse_limit (string, string_length (string))); +} + /* As for "limited" versions of previous 3 functions, they do the same thing, but are capped to some variable 'limit'. These functions have their own use-case, for example, if strings aren't null terminated, if you're not sure that they are null terminated, if we're dealing with binary (not textual) data (casted to char *), and many more cases. @@ -228,11 +232,11 @@ strings aren't null terminated, if you're not sure that they are null terminated int string_compare_limit (char * string_0, char * string_1, int limit) { int offset; - fatal_failure (string_0 == NULL, "string_compare_limit: Destination string is null pointer."); - fatal_failure (string_1 == NULL, "string_compare_limit: Source string is null pointer."); + fatal_failure (string_0 == NULL, "string_compare_limit: Destination string is null pointer."); // This is the new trend, check for unimportant things. + fatal_failure (string_1 == NULL, "string_compare_limit: Source string is null pointer."); // At least this isn't too verbose. I hope... - for (offset = 0; offset < limit; ++offset) { - if (string_0 [offset] != string_1 [offset]) { + for (offset = 0; offset < limit; ++offset) { // Now, we'll iterate until 'limit' is reached, but it can overrun. + if (string_0 [offset] != string_1 [offset]) { // All said here applies to next two functions as well... return (FALSE); } } @@ -277,4 +281,141 @@ char * string_concatenate_limit (char * string_0, char * string_1, int limit) { return (string_0); } +char * string_reverse_limit (char * string, int limit) { + int i; + + fatal_failure (string == NULL, "string_reverse: String is null pointer."); + + for (i = 0; i < limit / 2; ++i) { + char temporary = string [i]; + string [i] = string [limit - 1 - i]; + string [limit - 1 - i] = temporary; + } + + return (string); +} + +char * string_realign (char * string, int amount, char character) { + int offset, length; + + length = string_length (string); + + for (offset = 0; offset != length; ++offset) { + string [amount - offset - 1] = string [length - offset - 1]; + } + + for (offset = 0; offset != amount - length; ++offset) { + string [offset] = character; + } + + string [amount] = '\0'; + + return (string); +} + +void terminal_clear (void) { + echo ("\033[2J\033[H"); +} + +void terminal_colour (int colour, int effect) { + char format [8] = "\033[ ;3 m"; + + format [2] = (char) (effect % EFFECT_COUNT) + '0'; + format [5] = (char) (colour % COLOUR_COUNT) + '0'; + + echo (format); +} + +void terminal_cancel (void) { + echo ("\033[0m"); +} + +void terminal_show_cursor (int show) { + if (show != 0) { + echo ("\033[?25h"); + } else { + echo ("\033[?25l"); + } +} + +char * number_to_string (int number) { + int i, sign; + + static char string [32]; + + for (i = 0; i != 32; ++i) { + string [i] = '\0'; + } + + if (number == 0) { + string [0] = '0'; + string [1] = '\0'; + return (string); + } + + if (number < 0) { + number *= -1; + sign = 1; + } else { + sign = 0; + } + + for (i = (string [0] == '-'); number != 0; ++i) { + string [i] = (char) (number % 10) + '0'; + number /= 10; + } + + if (sign != 0) { + string [i] = '-'; + ++i; + } + + string [i] = '\0'; + + string_reverse (string); + + return (string); +} + +char * format_to_string (int number, int sign, int base, int amount, char character) { + int i; + + static char string [32]; + + for (i = 0; i != 32; ++i) { + string [i] = '\0'; + } + + if (number == 0) { + string [0] = '0'; + string [1] = '\0'; + + string_realign (string, amount, character); + + return (string); + } + + if (number < 0) { + number *= -1; + } + + for (i = (string [0] == '-'); number != 0; ++i) { + string [i] = "0123456789ABCDEF" [number % base]; + number /= base; + } + + if (sign != 0) { + string [i] = '-'; + ++i; + } + + string [i] = '\0'; + + string_reverse (string); + + string_realign (string, amount, character); + + return (string); +} + #endif diff --git a/chapters/chapter_0.h b/chapters/chapter_0.h index 5fb6ac9..94851cb 100644 --- a/chapters/chapter_0.h +++ b/chapters/chapter_0.h @@ -162,11 +162,6 @@ eye on how are they aligned and named. I'll reimplement some standard functions, #include // This one for open and O_ flags. #include // And this one for read, write, close and lseek. -#define SIGNAL_ARROW_UP (0X415B1B) // Just hardcoding some arrow key ASCII escape sequences, we'll explain them in later chapters... -#define SIGNAL_ARROW_DOWN (0X425B1B) -#define SIGNAL_ARROW_RIGHT (0X435B1B) -#define SIGNAL_ARROW_LEFT (0X445B1B) - enum { // This is completely unnecesary, but I don't care, it's a good showcase how boolean type can work, true is 1 and false is 0. FALSE, TRUE @@ -212,9 +207,21 @@ extern int string_length (char * string); // We deal with strings a lot in this extern int string_compare (char * string_0, char * string_1); // See how nicely they align, right? extern char * string_copy (char * string_0, char * string_1); extern char * string_concatenate (char * string_0, char * string_1); +extern char * string_reverse (char * string); // Notice last function, we didn't align ');'... extern int string_compare_limit (char * string_0, char * string_1, int limit); // These ones too, it's beautiful (in my opinion), tho some consider it useless. extern char * string_copy_limit (char * string_0, char * string_1, int limit); extern char * string_concatenate_limit (char * string_0, char * string_1, int limit); +extern char * string_reverse_limit (char * string, int limit); // And we align the last argument in this case, use whatever you prefer. + +extern char * string_realign (char * string, int amount, char character); + +extern void terminal_clear (void); +extern void terminal_colour (int colour, int effect); +extern void terminal_cancel (void); +extern void terminal_show_cursor (int show); + +extern char * number_to_string (int number); +extern char * format_to_string (int number, int sign, int base, int amount, char character); #endif diff --git a/chapters/chapter_1.c b/chapters/chapter_1.c index 7b37b6b..3ae5e97 100644 --- a/chapters/chapter_1.c +++ b/chapters/chapter_1.c @@ -190,23 +190,22 @@ header files, with prefix 'h', it's cancer. Why the extension wasn't just '.c=c+ */ int file_type (char * name) { - char * file_type_data [FILE_TYPE_COUNT] = { - ".txt", ".s", ".fasm", ".gasm", ".nasm", ".yasm", ".c", ".h", ".adb", ".ads", ".cpp", ".hpp" - }; + // Keep in mind that I'm intentionally being inconsistent, so you can see several ways to properly align your code, readability is the key to safety! + // Spacing between separate strings in array below is 10 characters, including comma and double quotes, and I "joined" curly braces too, it fits in 180 characters. + // You could break it up on curly braces, or put each string in it's own line if you wanted. + char * file_type_data [FILE_TYPE_COUNT] = { ".txt", ".s", ".fasm", ".gasm", ".nasm", ".yasm", ".c", ".h", ".adb", ".ads", ".cpp", ".hpp" }; int type; - while (* name != '.') { - ++name; - } + for (; * name != '.'; ++name); // We offset the 'name' until we reach fullstop character. - for (type = 0; type != FILE_TYPE_COUNT; ++type) { - if (string_compare (name, file_type_data [type]) != 0) { + for (type = 0; type != FILE_TYPE_COUNT; ++type) { // Then we check if it's one from this array by comparing them sequentially. + if (string_compare (name, file_type_data [type]) != 0) { // If it is, we return the value of enumeration of file types. return (type); } } - return (-1); + return (-1); // If it's not in array, we return -1, so we don't access the wrong value in some other array. } void * file_record (char * name) { diff --git a/chapters/chapter_1.h b/chapters/chapter_1.h index ede9542..65e845d 100644 --- a/chapters/chapter_1.h +++ b/chapters/chapter_1.h @@ -193,6 +193,30 @@ ASCII table: |_______________________________________________________________________________|_______________________________________________________________________________| You can see that values of 'A' ... 'Z', 'a' ... 'z' and '0' ... '9' are sequential, but symbols and "system" characters are mixed up. + +In C language, we have C source files with the extension '.c', and C header files with the extension '.h'. Both of those are just plain text files, and please use 7-bit ASCII +encoding, since it's common sense, UTF is cancer, and 8-bit ASCII is for enlightened people like Terrence Andrew Davis. C language is completely separate (on some C compilers) +from its' preprocessor, whose directives start with '#' character, continue on '\' character and break on '\n' (read: LINE FEED) character. + +@C +#include // Copy the entire file from '/usr/include/' directory into this file, on the place where it was specified. +#include "path/to/file/file_name.h" // Copy the entire file from current directory into this file, again on the place where it was specified. + +#define SOMETHING // This will add additional information to the preprocessor about this file, it's mostly used for flags and header-guards. +#undef SOMETHING // This will remove that additional information you've provided... +#if SOMETHING // If SOMETHING (condition obviously) is true, then code until '#elif', '#else' or '#endif' will be included. +#ifdef SOMETHING // If SOMETHING was previously '#define'-d, then code until '#elif', '#else' or '#endif' will be included. +#ifndef SOMETHING // If SOMETHING wasn't (NOT!) previously '#define'-d, then code until '#elif', '#else' or '#endif' will be included. +#elif // Essentially "else if" for preprocessor, it's very ugly, and nesting them looks bad and is a bad practice. +#else // Essentially "else" for preprocessor, I don't think I ever used it in my entire life, but I saw other people use it. +#endif // End if... Self-explanatory, and a sad thing that we need to ruin the beautiful C code with it. +@ + +Okay, that's all you really need to know about C preprocessor, since we won't use it much. You can write a completely pure C project, using only C language, but you'll end up with +copying and pasting a lot of code, especially external function and variable declarations. Because of that we need '#include' directive, and because of it, we need header guards, +so it's all C-hating in the end. However, we need to cover some simple macros, so you can deal with other peoples' code bases. Remember, the less "building blocks" you have, if +you learn them well, you can make anything, and you should be proud of "reinventing the wheel". If wheels weren't reinvented over and over again, then some expensive BMW would've +wooden wheels attached to it. */ extern int character_is_uppercase (char character); // Notice how we align those functions, I believe this improves the readability of any program, in any programming language. diff --git a/chapters/chapter_2.c b/chapters/chapter_2.c index 2d43dc1..c8a2300 100644 --- a/chapters/chapter_2.c +++ b/chapters/chapter_2.c @@ -18,8 +18,8 @@ instruction, which magically does something, like open or close a file descripto you use keyword 'sizeof' on a string, it'll count null terminator, so it'll have value 14, and type 'size_t'. It's provided in header file. @C -write ( // mov rax 1 ; Literal of Linux write system call. - STDOUT_FILENO, // mov rdi 1 ; Literal of standard output file descriptor. +write ( // mov rax 1 ; Literal of Linux write system call, defined internally. + STDOUT_FILENO, // mov rdi 1 ; Literal of standard output file descriptor, defined as 'STDOUT_FILENO'. "Hello world!\n", // mov rsi X ; Address of our string. sizeof ("Hello world!\n") // mov rdx [Y] ; Literal of size of our string. ); // syscall ; Ask kernel to do some work. @@ -97,4 +97,242 @@ void (* hello_world [4]) (void) = { hello_world_3 }; +/* +Now, we'll talk more about cursed functions! I broke code formatting rules for this, but it's worth it, time to learn. +*/ + +static char curses_format [CURSES_FORMAT + 1] = "\033[-;3-m-\033[0m"; +static char curses_cursor [CURSES_CURSOR + 1] = "\033[---;---H"; + +static char * curses_screen = NULL; + +static int curses_action_count = 0; +static int * curses_activator = NULL; + +static void (* * curses_action) (void) = NULL; + +static struct termios curses_old_terminal; +static struct termios curses_new_terminal; + +static void curses_free (void) { + curses_screen = deallocate (curses_screen); + curses_activator = deallocate (curses_activator); + curses_action = deallocate (curses_action); + + terminal_clear (); + + fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, "tcsetattr: Failed to set default terminal attributes."); +} + +static char * curses_screen_offset (int x, int y) { + // log_in (LOG_FAILURE, x <= -1, "curses_screen_offset: X position is below the lower bound."); + // log_in (LOG_FAILURE, y <= -1, "curses_screen_offset: Y position is below the lower bound."); + // log_in (LOG_FAILURE, x >= curses_screen_width, "curses_screen_offset: X position is above the upper bound."); + // log_in (LOG_FAILURE, y >= curses_screen_height, "curses_screen_offset: Y position is above the upper bound."); + + limit (& x, 0, curses_screen_width - 1); + limit (& y, 0, curses_screen_height - 1); + + return (& curses_screen [CURSES_REVERT + CURSES_FORMAT * (y * curses_screen_width + x)]); +} + +static char * curses_format_character (char character, int colour, int effect) { + // log_in (LOG_WARNING, character_is_invisible (character), "curses_format_character: Can not format invisible characters."); + // log_in (LOG_FAILURE, colour >= COLOUR_COUNT, "curses_format_character: Colour is invalid enumeration value."); + // log_in (LOG_FAILURE, effect >= EFFECT_COUNT, "curses_format_character: Effect is invalid enumeration value."); + + if (character_is_invisible (character) != 0) { + character = ' '; + } + + colour %= COLOUR_COUNT; + effect %= EFFECT_COUNT; + + switch (effect) { + case EFFECT_NORMAL: effect = 0; break; + case EFFECT_BOLD: effect = 1; break; + case EFFECT_ITALIC: effect = 3; break; + case EFFECT_UNDERLINE: effect = 4; break; + case EFFECT_BLINK: effect = 5; break; + case EFFECT_REVERSE: effect = 7; break; + default: effect = 0; break; + } + + curses_format [2] = (char) effect + '0'; + curses_format [5] = (char) colour + '0'; + curses_format [7] = character; + + // log_out ("curses.log"); + + return (curses_format); +} + +static void curses_idle (void) { return; } // If you have a lot of short functions that are intended to be in array of function pointers, you can align them like this. +static void curses_exit (void) { curses_active = 0; } + +int curses_realign_x = 0; +int curses_realign_y = 0; +int curses_tab_width = 8; +int curses_character = 0; +int curses_signal = SIGNAL_NONE; +int curses_screen_width = 0; +int curses_screen_height = 0; +int curses_active = 1; + +/* +External function definitions, those found in "chapter_2.h" header file. +*/ + +void curses_configure (void) { + struct winsize screen_dimension; + + atexit (curses_free); + + fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "ioctl: Failed to get terminal dimensions."); + + curses_screen_width = (int) screen_dimension.ws_col; + curses_screen_height = (int) screen_dimension.ws_row; + + fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, "tcgetattr: Failed to get default terminal attributes."); + + curses_new_terminal = curses_old_terminal; + + curses_new_terminal.c_cc [VMIN] = (unsigned char) 0; + curses_new_terminal.c_cc [VTIME] = (unsigned char) 1; + + curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST); + curses_new_terminal.c_cflag |= (unsigned int) (CS8); + curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG); + + fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, "tcsetattr: Failed to set reverse terminal attributes."); + + curses_screen = allocate (CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height + CURSES_CURSOR + 1); + + curses_bind (SIGNAL_ESCAPE, curses_exit); + + terminal_clear (); + + string_copy (& curses_screen [0], "\033[H"); +} + +void curses_synchronize (void) { + int signal; + + curses_signal = curses_character = signal = 0; + + out (curses_screen, CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height + CURSES_CURSOR); + + in (& signal, 4); + + curses_character = signal; + + if (signal == '\033') { + curses_signal |= SIGNAL_ESCAPE; + } else if (character_is_digit (signal) != 0) { + curses_signal |= SIGNAL_0 + (int) (signal - '0'); + } else if (character_is_lowercase (signal) != 0) { + curses_signal |= SIGNAL_A + (int) (signal - 'a'); + } else if (character_is_uppercase (signal) != 0) { + curses_signal |= SIGNAL_A + (int) (signal - 'A'); + curses_signal |= SIGNAL_SHIFT; + } else { + curses_signal = SIGNAL_NONE; + } + + for (signal = 0; signal != curses_action_count; ++signal) { + if (curses_signal == curses_activator [signal]) { + curses_action [signal] (); + } + } +} + +void curses_bind (int signal, void (* action) (void)) { + ++curses_action_count; + + curses_activator = reallocate (curses_activator, curses_action_count * (int) sizeof (* curses_activator)); + curses_action = reallocate (curses_action, curses_action_count * (int) sizeof (* curses_action)); + + curses_activator [curses_action_count - 1] = signal; + curses_action [curses_action_count - 1] = action; +} + +void curses_unbind (int signal) { + (void) signal; + + curses_activator [curses_action_count - 1] = SIGNAL_NONE; + curses_action [curses_action_count - 1] = curses_idle; + + --curses_action_count; +} + +void curses_render_cursor (int x, int y) { + x %= 1000; + y %= 1000; + + string_copy_limit (curses_cursor + 2, string_realign (number_to_string (y + 1), 3, '0'), 3); + string_copy_limit (curses_cursor + 6, string_realign (number_to_string (x + 1), 3, '0'), 3); + + string_copy_limit (& curses_screen [CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height], curses_cursor, CURSES_CURSOR); +} + +void curses_render_character (char character, int colour, int effect, int x, int y) { + if ((x >= curses_screen_width) || (y >= curses_screen_height)) { + return; + } + + string_copy_limit (curses_screen_offset (x, y), curses_format_character (character, colour, effect), CURSES_FORMAT); +} + +void curses_render_background (char character, int colour, int effect) { + int x, y; + + for (y = 0; y != curses_screen_height; ++y) { + for (x = 0; x != curses_screen_width; ++x) { + curses_render_character (character, colour, effect, x, y); + } + } +} + +/* +We've mentioned before, in chapter zero, that you can implement 'string_*' functions by 'string_*_limit', and here's an example of that. +*/ + +int curses_render_string (char * string, int colour, int effect, int x, int y) { + return (curses_render_string_limit (string, string_length (string), colour, effect, x, y)); +} + +int curses_render_number (int number, int colour, int effect, int x, int y) { + return (curses_render_number_limit (number, 32, colour, effect, x, y)); +} + +int curses_render_string_limit (char * string, int limit, int colour, int effect, int x, int y) { + int offset; + + for (offset = 0; offset != limit; ++offset) { + if (string [offset] == '\n') { + x = 0; + y += 1; + } else if (string [offset] == '\t') { + x += 8; + } else { + curses_render_character (string [offset], colour, effect, x, y); + x += 1; + } + } + + return (limit); +} + +int curses_render_number_limit (int number, int limit, int colour, int effect, int x, int y) { + (void) number; + (void) limit; + (void) colour; + (void) effect; + (void) x; + (void) y; + + return (limit); +} + #endif diff --git a/chapters/chapter_2.h b/chapters/chapter_2.h index 3381b11..8edbc37 100644 --- a/chapters/chapter_2.h +++ b/chapters/chapter_2.h @@ -70,4 +70,70 @@ extern void hello_world_3 (void); extern void (* hello_world [4]) (void); // External (global) variable with name 'hello_world' of type 'array of 4 function pointers with no input/output'. +/* +Alright, we'll never use those 4 functions, but now you know how to declare any function, it's time for more serious examples. Below you'll see some scary looking cursed functions +that interact with the terminal in which we're executing this program. We'll change the terminal from default (sane) mode to raw (insane) mode. That means the characters we press +on our keyboard won't be printed in terminal, like usual. That'll allow us to make cursed C program that'll scare away all GUI fanatics. In the ancient times, when people used +teletypewriters, terminal was obscure magic. Nowdays, parents scare their children into obedience by showing them terminals. Like, if you don't behave, I'll edit X11 scripts and +you won't be able to see icons, you won't pass the Login text on your screen, you'll never open your web browser again (lynx rules). +*/ + +#include // Terminal input, output and configuration. +#include // Rest is some Linux related cancer... +#include +#include + +#include "chapter_0.h" // We use functions declared in these two header files, so in order to make them visible, we included those files here. +#include "chapter_1.h" + +#define SIGNAL_ARROW_UP (0X415B1B) // Just hardcoding some arrow key ASCII escape sequences, we'll explain them in later chapters... +#define SIGNAL_ARROW_DOWN (0X425B1B) +#define SIGNAL_ARROW_RIGHT (0X435B1B) +#define SIGNAL_ARROW_LEFT (0X445B1B) + +#define SIGNAL_CONTROL (0X1000000) +#define SIGNAL_SHIFT (0X2000000) +#define SIGNAL_ALTERNATE (0X4000000) +#define SIGNAL_SYSTEM (0X8000000) + +#define CURSES_FORMAT ((int) sizeof ("\033[-;3-m-\033[0m") - 1) // We'll use these three macros through-out cursed functions, I'm following formatting rules, so it's here... +#define CURSES_REVERT ((int) sizeof ("\033[H") - 1) +#define CURSES_CURSOR ((int) sizeof ("\033[---;---H") - 1) + +enum { + SIGNAL_NONE, + SIGNAL_ANY, + SIGNAL_A, SIGNAL_B, SIGNAL_C, SIGNAL_D, SIGNAL_E, SIGNAL_F, SIGNAL_G, SIGNAL_H, + SIGNAL_I, SIGNAL_J, SIGNAL_K, SIGNAL_L, SIGNAL_M, SIGNAL_N, SIGNAL_O, SIGNAL_P, + SIGNAL_Q, SIGNAL_R, SIGNAL_S, SIGNAL_T, SIGNAL_U, SIGNAL_V, SIGNAL_W, SIGNAL_X, + SIGNAL_Y, SIGNAL_Z, SIGNAL_0, SIGNAL_1, SIGNAL_2, SIGNAL_3, SIGNAL_4, SIGNAL_5, + SIGNAL_6, SIGNAL_7, SIGNAL_8, SIGNAL_9, SIGNAL_ESCAPE, SIGNAL_TABULATOR, SIGNAL_RETURN, SIGNAL_NEW_LINE, + SIGNAL_SLASH, SIGNAL_BACKSLASH, SIGNAL_QUOTE, SIGNAL_BACKQUOTE, SIGNAL_SPACE, SIGNAL_BACKSPACE, SIGNAL_DOT, SIGNAL_COMMA, + SIGNAL_CITE, SIGNAL_CAPS_LOCK, SIGNAL_L_BRACKET, SIGNAL_R_BRACKET, SIGNAL_MINUS, SIGNAL_EQUAL, + SIGNAL_COUNT +}; + +extern int curses_character; +extern int curses_signal; +extern int curses_screen_width; +extern int curses_screen_height; +extern int curses_active; + +extern void curses_configure (void); +extern void curses_synchronize (void); + +extern void curses_bind (int signal, void (* action) (void)); +extern void curses_unbind (int signal); + +extern void curses_render_cursor (int x, int y); + +extern void curses_render_character (char character, int colour, int effect, int x, int y); +extern void curses_render_background (char character, int colour, int effect); + +// Remember that in chapter zero, I've separated 'string_*' and 'string_*_limit' functions. Now, there's always more ways to logically organize your code, for example, as below: +extern int curses_render_string (char * string, int colour, int effect, int x, int y); +extern int curses_render_number (int number, int colour, int effect, int x, int y); +extern int curses_render_string_limit (char * string, int limit, int colour, int effect, int x, int y); +extern int curses_render_number_limit (int number, int limit, int colour, int effect, int x, int y); + #endif diff --git a/xhartae.c b/xhartae.c index c6974a0..87f6686 100644 --- a/xhartae.c +++ b/xhartae.c @@ -90,30 +90,6 @@ One sane C program should have the following structure (please keep in mind that 6) Internal function then variable definition. 7) External function then variable definition. 8) Main function. - -In C language, we have C source files with the extension '.c', and C header files with the extension '.h'. Both of those are just plain text files, and please use 7-bit ASCII -encoding, since it's common sense, UTF is cancer, and 8-bit ASCII is for enlightened people like Terrence Andrew Davis. C language is completely separate (on some C compilers) -from its' preprocessor, whose directives start with '#' character, continue on '\' character and break on '\n' (read: LINE FEED) character. - -@C -#include // Copy the entire file from '/usr/include/' directory into this file, on the place where it was specified. -#include "path/to/file/file_name.h" // Copy the entire file from current directory into this file, again on the place where it was specified. - -#define SOMETHING // This will add additional information to the preprocessor about this file, it's mostly used for flags and header-guards. -#undef SOMETHING // This will remove that additional information you've provided... -#if SOMETHING // If SOMETHING (condition obviously) is true, then code until '#elif', '#else' or '#endif' will be included. -#ifdef SOMETHING // If SOMETHING was previously '#define'-d, then code until '#elif', '#else' or '#endif' will be included. -#ifndef SOMETHING // If SOMETHING wasn't (NOT!) previously '#define'-d, then code until '#elif', '#else' or '#endif' will be included. -#elif // Essentially "else if" for preprocessor, it's very ugly, and nesting them looks bad and is a bad practice. -#else // Essentially "else" for preprocessor, I don't think I ever used it in my entire life, but I saw other people use it. -#endif // End if... Self-explanatory, and a sad thing that we need to ruin the beautiful C code with it. -@ - -Okay, that's all you really need to know about C preprocessor, since we won't use it much. You can write a completely pure C project, using only C language, but you'll end up with -copying and pasting a lot of code, especially external function and variable declarations. Because of that we need '#include' directive, and because of it, we need header guards, -so it's all C-hating in the end. However, we need to cover some simple macros, so you can deal with other peoples' code bases. Remember, the less "building blocks" you have, if -you learn them well, you can make anything, and you should be proud of "reinventing the wheel". If wheels weren't reinvented over and over again, then some expensive BMW would've -wooden wheels attached to it. */ int main (int argc, char * * argv) {