xhartae/chapters/chapter_0.h

201 lines
11 KiB
C
Raw Normal View History

/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic
Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/
#ifndef CHAPTER_0_HEADER
#define CHAPTER_0_HEADER
/*
It's very important that your code is aligned, readable and safe. So, we'll talk about it even before the first chapter, the so-called "zero chapter". I write assembly and Ada
beside C, but still, 90% of my projects are written in C programming language! Why? Because C is like a girl that's a bit older than you, quiet but very smart and respectable, and
you don't want to piss her off. Ada is more like nerdy girl who doesn't know what she wants, while assembly is ghost girl in your closet that you pretend not to see at night. So,
this Ada girl was my first serious love, and she had a book "Ada Coding Standard", which is like a bible to her. It's a bit fanatical, but it has some good points which I'll
discuss below without copy/paste, and apply to C.
*/
/*
Lets see some good examples of C code (in my opinion obviously), I'll provide few of them, and note that I use the first style in them. Needless to say, as this book is aimed to
people who don't know C programming language, or are in phase of learning it, you should (and eventually will) develop your own style of writing it, but you shouldn't force it at
the start, it should happen over time, naturally. Just be sure to always be consistent, and to avoid anything that'll generate compiler warnings.
*/
/*
General code formatting should follow these rules in C programming language:
- Always use tabs for indentation, and spaces for alignment. You'll hear people say the otherwise, don't trust them, it's pure cancer.
- Separate most (not all!) operators with space before and after it. We'll provide exceptional cases for this rule below.
- Align most (not all!) operators horizontally, and logical units vertically. Again, examples are the best showcase.
- Always use curly braces and round braces, even when they're not required by the compiler. Most linters warn about this.
- Avoid writing a lot of comments, or avoid them completely, except for license notice, this book is an exception!
- Think very carefully if you'll limit the line length, it depends on your workflow and attention span... For me, 180 characters per line.
- If you want, use pagination, but I don't recommend it when working with C. I use it in Ada, because comments there start with "--".
- Always use snake case (this_naming_style), for enumerations and macros (THIS_STYLE), and never put underscore before or after the identifier.
Spacing:
- Before and after:
A: B: C: D: E: F:
+ += & &= && ==
- -= | |= || !=
* *= ^ ^= ! <=
/ /= << <<= ~ >=
% %= >> >>= ? >
= : <
- Before:
( { [
- After:
) } ] , ;
- None (unary + and -):
. -> " ' ++ -- + -
Exceptions:
- Merge consecutive opened or closed braces, for example, like when you're nesting function calls.
- When declaring functions, align return types and open braces, and by taste, argument types for logical units.
- When declaring variables, align types and asignment operators, and by taste, pointer or array operators.
Naming:
- Have you ever wondered, what the hell is stdio, unistd, stdint, termios, errno, strcat, strchr, strndupa, memcpy, atoi, fgetc, puts, lseek...? I did wonder.
- Are identifiers such as string_concatenate, memory_copy, error_id, integer, boolean, constant, string_to_integer, file_offset too long to type...? I think not.
All that aside, C is an old programming language, and people who have made it knew a lot more about how computers work at their time than most people know nowdays. Hardware got
faster and cheaper, but also more complex. We have enough memory today to edit our text files with word-wrapping enabled, highlight the syntax, and to store large files due to
very long identifiers, 8-space-wide indentation instead of a single tab and overly complicated OOP code. If you can handle those names above, feel free to use them, but be
consistent. I can't handle them, so I tolerate them with C keywords, because I'd actually prefer "constant / integer / character" over "const / int / char"... You'll notice that
C has mixed them in keywords, and most standard library headers mix them too...
- Keywords: register double short signed break while / int char extern auto enum struct
- Headers: string memory limits time complex threads / stdio stdlib stdint unistd fcntl termios
- Functions: read write open close exit clock / strncmp memcpy atoi fputc tcsetattr usleep
About that, I don't even know where to begin... But lets ignore that for now and focus on code formatting...
There's not much to say here, we'll talk about function declarations more in later chapters, as they are optional, but I like to use them. However, you should avoid to use too
many function agruments, and always place them in consistent and logical order.
*/
/**
// Internal and external function declaration:
static int string_copy_limit (char * string_0, char * string_1, int limit);
extern int32_t string_copy (char * string_a,
char * string_b,
int32_t count);
extern size_t copy_string_n (
string_t a,
string_t b,
size_t n);
**/
/*
Internal ('static') and external ('extern') variable declarations are different from function declarations, because you need to initialize internal variables to some value, I like
to provide either "zero" value for them, with the corresponding type (0, 0.0, '\0', NULL...), or an invalid value (-1, EOF...). Some C compilers and linters will warn you about
redeclaring them, some will warn you that they're already initialized to zero, so when you some across those warnings, you'll know how to fix them. I hate this part of C...
*/
/**
// Internal and external variable declaration:
static int curses_active = 0;
static char curses_signal = '\0';
static char * curses_screen = NULL;
extern unsigned int positive;
extern int negative;
extern int * * coordinate_system;
static void (* encode_type_0 [TYPE_0_COUNT]) (void) = { NULL };
static char * (* encode_type_1 [TYPE_1_COUNT]) (int l) = { NULL };
static int (* encode_type_2 [TYPE_2_COUNT]) (int l, int r) = { NULL };
extern xcb_window_t blesses_window;
extern xcb_gcontext_t blesses_context;
extern xcb_pixmap_t blesses_pixmap;
extern xcb_connection_t * blesses_connection;
extern xcb_screen_t * blesses_screen;
extern xcb_image_t * blesses_image;
**/
/*
Only for 'main' function, you shouldn't add 'static' or 'extern' keywords before it. Every C file needs to have exactly one 'main' function, it's the programs' entry point. Also,
some people like to define their own types, with keyword 'typedef', I'm not a fan of it, since in C types are also keywords unlike in Ada. Again, it'll become more clean in future
chapters why I dislike user-defined types, unions and structures.
*/
/**
// Main function:
int main (int argc, char * * argv) {
int32_t main (int32_t argc,
char * argv []) {
number_t main (
number_t argc,
string_t argv []) {
**/
/*
Now, I'll write some basic functions that'll be used later in the program, so you can see that code formatting I've spent whole hour writing. Don't mind what they do, just keep an
eye on how are they aligned and named. I'll reimplement some standard functions, and you can revisit them after reading few more chapters, it'll be more understandable then.
*/
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define SIGNAL_ARROW_UP (0X415B1B)
#define SIGNAL_ARROW_DOWN (0X425B1B)
#define SIGNAL_ARROW_RIGHT (0X435B1B)
#define SIGNAL_ARROW_LEFT (0X445B1B)
enum { /* I like to align enumerations with 10, 20 or 40 characters per name, and optionally use NAME_ as prefix and NAME_COUNT as last element. */
EFFECT_NORMAL, EFFECT_BOLD, EFFECT_ITALIC, EFFECT_UNDERLINE, EFFECT_BLINK, EFFECT_REVERSE,
EFFECT_COUNT
};
enum { /* Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays. */
COLOUR_GREY, COLOUR_RED, COLOUR_GREEN, COLOUR_YELLOW, COLOUR_BLUE, COLOUR_PINK, COLOUR_CYAN, COLOUR_WHITE,
COLOUR_COUNT
};
enum { /* This is also one of my preferences, to use CHARACTER_NULL or CHARACTER_LINE_FEED instead of '\0' or '\n' in special (non-string) cases. */
CHARACTER_NULL, CHARACTER_START_HEADER, CHARACTER_START_TEXT, CHARACTER_END_TEXT,
CHARACTER_END_TRANSMISSION, CHARACTER_ENQUIRY, CHARACTER_ACKNOWLEDGE, CHARACTER_BELL,
CHARACTER_BACKSPACE, CHARACTER_TAB_HORIZONTAL, CHARACTER_LINE_FEED, CHARACTER_TAB_VERTICAL,
CHARACTER_FORM_FEED, CHARACTER_CARRIAGE_RETURN, CHARACTER_SHIFT_OUT, CHARACTER_SHIFT_IN,
CHARACTER_DATA_LINK_ESCAPE, CHARACTER_DEVICE_CONTROL_1, CHARACTER_DEVICE_CONTROL_2, CHARACTER_DEVICE_CONTROL_3,
CHARACTER_DEVICE_CONTROL_4, CHARACTER_NOT_ACKNOWLEDGE, CHARACTER_SYNCHRONOUS_IDLE, CHARACTER_END_TRANSMISSION_BLOCK,
CHARACTER_CANCEL, CHARACTER_END_MEDIUM, CHARACTER_SUBSTITUTE, CHARACTER_ESCAPE,
CHARACTER_FILE_SEPARATOR, CHARACTER_GROUP_SEPARATOR, CHARACTER_RECORD_SEPARATOR, CHARACTER_UNIT_SEPARATOR,
CHARACTER_COUNT
};
extern void in (void * data, int size); /* We'll use these functions later as core standard input/output functions. */
extern void out (void * data, int size);
extern void echo (char * data); /* Function 'echo' behaves similar to 'out', but it's easier to use because it doesn't require size. */
extern void fatal_failure (int condition, char * message); /* Some functions fail, and sometimes we want to abort everything, crash and leak memory, we just don't care. */
extern void limit (int * value, int minimum, int maximum);
extern void * allocate ( int size); /* Core memory management functions with some minimal error checking. */
extern void * reallocate (void * data, int size);
extern void * deallocate (void * data );
#endif