Added cursed functions...

This commit is contained in:
Ognjen Milan Robovic 2023-11-10 13:30:15 -05:00
parent e4228e8d8b
commit cb619d884c
7 changed files with 495 additions and 44 deletions

View File

@ -220,6 +220,10 @@ char * string_concatenate (char * string_0, char * string_1) {
return (result); 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 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. 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 string_compare_limit (char * string_0, char * string_1, int limit) {
int offset; int offset;
fatal_failure (string_0 == NULL, "string_compare_limit: Destination 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."); 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) { 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]) { if (string_0 [offset] != string_1 [offset]) { // All said here applies to next two functions as well...
return (FALSE); return (FALSE);
} }
} }
@ -277,4 +281,141 @@ char * string_concatenate_limit (char * string_0, char * string_1, int limit) {
return (string_0); 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 #endif

View File

@ -162,11 +162,6 @@ eye on how are they aligned and named. I'll reimplement some standard functions,
#include <fcntl.h> // This one for open and O_ flags. #include <fcntl.h> // This one for open and O_ flags.
#include <unistd.h> // And this one for read, write, close and lseek. #include <unistd.h> // 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. 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, FALSE,
TRUE 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 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_copy (char * string_0, char * string_1);
extern char * string_concatenate (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 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_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_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 #endif

View File

@ -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) { int file_type (char * name) {
char * file_type_data [FILE_TYPE_COUNT] = { // 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!
".txt", ".s", ".fasm", ".gasm", ".nasm", ".yasm", ".c", ".h", ".adb", ".ads", ".cpp", ".hpp" // 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; int type;
while (* name != '.') { for (; * name != '.'; ++name); // We offset the 'name' until we reach fullstop character.
++name;
}
for (type = 0; type != FILE_TYPE_COUNT; ++type) { 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 (string_compare (name, file_type_data [type]) != 0) { // If it is, we return the value of enumeration of file types.
return (type); 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) { void * file_record (char * name) {

View File

@ -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. 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 <path/to/file/file_name.h> // 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. 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.

View File

@ -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 <unistd.h> header file. 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 <unistd.h> header file.
@C @C
write ( // mov rax 1 ; Literal of Linux write system call. write ( // mov rax 1 ; Literal of Linux write system call, defined internally.
STDOUT_FILENO, // mov rdi 1 ; Literal of standard output file descriptor. 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. "Hello world!\n", // mov rsi X ; Address of our string.
sizeof ("Hello world!\n") // mov rdx [Y] ; Literal of size of our string. sizeof ("Hello world!\n") // mov rdx [Y] ; Literal of size of our string.
); // syscall ; Ask kernel to do some work. ); // syscall ; Ask kernel to do some work.
@ -97,4 +97,242 @@ void (* hello_world [4]) (void) = {
hello_world_3 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 #endif

View File

@ -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'. 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 <termios.h> // Terminal input, output and configuration.
#include <sys/ioctl.h> // Rest is some Linux related cancer...
#include <sys/types.h>
#include <sys/stat.h>
#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 #endif

View File

@ -90,30 +90,6 @@ One sane C program should have the following structure (please keep in mind that
6) Internal function then variable definition. 6) Internal function then variable definition.
7) External function then variable definition. 7) External function then variable definition.
8) Main function. 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 <path/to/file/file_name.h> // 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) { int main (int argc, char * * argv) {