Преглед изворни кода

Read me file and chapter zero...

master
Ognjen Milan Robovic пре 6 месеци
родитељ
комит
6b5003ae7f
6 измењених фајлова са 146 додато и 36 уклоњено
  1. +61
    -1
      README.md
  2. +56
    -20
      chapters/chapter_0.c
  3. +12
    -7
      chapters/chapter_0.h
  4. +3
    -3
      chapters/chapter_2.c
  5. +3
    -5
      chapters/chapter_2.h
  6. +11
    -0
      xhartae.c

+ 61
- 1
README.md Прегледај датотеку

@@ -1,3 +1,63 @@
# xhartae

More to come...
xhartae -- Program and book for learning the C programming language.

- This is still work in progress, and so far, this is the most complex project I have, be patient, I'll finish it.
- Everything related to my libraries is clean of all warning options on Clang, GCC and Valgrind.

Compile:
```bash
$ sh compile.sh
```

Install:
```bash
$ sudo sh install.sh
```

Use:
```bash
$ xhartae
```

This is the ultimate C programming language guide, brought to you by Ognjen 'xolatile' Milan Robovic. I'm not a native English speaker nor a real programmer, only a hobbyist, so
this "book" will be full of grammatical mistakes, but not compiler warnings. Please be patient, C is a small language, even for the time when it was made, so if you ignore my
rambling and focus on what's written outside of the comments, you'll easily learn it. Good luck and have fun...

With that being said, I'll tell you the honest truth. No amount of books or source code you read (that's written in C or any other language) will make you good in programming (in
C or any other language). You get good in programming by writing the programs. Knowing what some statement, expression or library function will do is just a small advantage that's
saving you the time in order not to read (read yet again...) some documentation or specification. Sure, you can write literal machine code for some CPU instruction set, but you
still need to know what instructions are supported and how they translate to machine code. The sad thing about programming is that you need very small subset of information to
achieve creating almost anything, and yet, you need huge set of informations to do it in more concise way. That's the tradeoff.

Either learn very small subset of "building materials" and "architecture", then proceed building sewers, roads, houses, malls, factories, skyscrapers and in the end create a town,
or learn huge set of "pre-made houses, pre-made factories, pre-made road blocks", and create a same-looking town. If you use any kind of library functions, even the one's we'll
use in some parts of this program, you'll end up as a "interior designer" rather than an "architect". C programming language is the minimal kind of tool that's widely supported
and lets do write "quick assembly", we'll have entire chapter about assembly and machine code, so you can make your own language.

We're dealing with a low-level functional (and procedural) programming language called C. So, disengage all safety protocols, think twice, write once, enter the Great C and learn
to sail on it after some practice. This will never be a book. It has no readers. It's not even printed. It's pages are files. It's cover is a folder. This will never be a book. I,
for the most part, am having fun writing this, same as I have fun while programming. You won't get a job after reading this "book", only some knowledge.

How to read this book?

- First of all, read the "README.md" file in base directory. Run scripts there in the order they're listed.
- Now, make a copy of 'xhartae' folder somewhere, and run '$ xhartae' from there, or just read the source.
- Feel free to modify (edit) that copy, if you can't fix some error, just replace it with the original one.

When you read some book about a programming language, you can't modify it and recompile it. You can do it with this book, so it's not really a "book", but at the same time it is.
If you fuck up something and don't know how to fix it, you'll easily replace that folder with the working one, which you can also download from my GitLain repository. If you're,
for example, learning about switch statement, you can just write it inside this book, recompile it and run it. If compiler spits out warnings or error that you can't fix, just
delete that part of the code, and go on with your life...

Why should you learn or use C programming language in 2023?

- C was inspiration for many newer programming languages for good reasons.
- C can interface with huge variety of other distinct programming languages.
- C can be a lot more readable, faster and easier if used well.

Goal of this so-called book?

- You'll be able to write your own compiler or interpretter, for your own language after reading this, and many more programs.
- You might learn something new. My target audience is people who don't know C languages, but maybe there's something new for you.
- You won't (hopefully) buy into big ideas and paradigms about programming, you'll just create programs, and have fun doing so.

+ 56
- 20
chapters/chapter_0.c Прегледај датотеку

@@ -127,10 +127,10 @@ that the loop shouldn't have a body (code block {}). I just put ';' on the same
now, and since we've already declared them in header file "chapter_0.h" we can define them and call them in whatever order we want. Nice.

@C
// Simple example of how we could make it dependable on 'string_*_limit' function...
// Simple example of how we could make 'string_*' function dependable on 'string_*_limit' function...

int string_compare (char * string_0, char * string_1) {
return (string_0, string_1, string_length (string_0));
return (string_compare_limit (string_0, string_1, string_length (string_0));
}
@
*/
@@ -226,7 +226,9 @@ char * string_reverse (char * string) { // Example of implementing "unlimited" v

/*
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. I won't
write comments for 'string_copy_limit', 'string_concatenate_limit' and 'string_reverse_limit', try to read them and understand what kind of operation they'll perform with your
current knowledge of C language.
*/

int string_compare_limit (char * string_0, char * string_1, int limit) {
@@ -237,11 +239,11 @@ int string_compare_limit (char * string_0, char * string_1, int limit) {

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);
return (FALSE); // As soon as 2 characters mismatch, they're not same, we return FALSE.
}
}

return (TRUE);
return (TRUE); // Otherwise, we're reached the end, they're same, we return TRUE.
}

char * string_copy_limit (char * string_0, char * string_1, int limit) {
@@ -295,24 +297,58 @@ char * string_reverse_limit (char * string, int limit) {
return (string);
}

char * string_realign (char * string, int amount, char character) {
int offset, length;
/*
We'll use this function in many other chapters (in other C source files!), but we'll be careful, since compiler can't catch all the mistakes we make. Lets listen a story!

Compiler likes you because you are his master. You tell him what to do (with passing flags as 'argv'), you give him the tool (your text files) and he'll do it. Sometimes he can
complain, like "you gave me a shovel to chop some firewood" or "you gave me an axe to clean the leaves from the road", and he can't do that task. But if you give him a proper tool
for proper task, he'll do it and won't complain at all. However, sometimes, you give him an imperfect tool (your C program full of subtle bugs) and he won't notice it. He'll do
the job (translate bunch of ASCII characters into bunch of bytes), and say he's finished. Then you go out and see the results (run your executable), and it's all mess! You're like
"What the hell, do as I say!", but he doesn't know what he did wrong... And in fact, it was your fault for giving him a imperfect tool all along. That's why we sometimes need more
difficult to use servants. When you, as his master, tell him to do some job for you, he'll complain endlessly. You should use all your servants appropriately, each of them for
different kind of task, and you'll learn to choose them wisely.

Now, funny story aside, some languages are considered safe because they won't compile your code if they find any kind of syntax mistake. Ada is very strict programming language,
we'll talk about it in later chapters, as Ada compilers complain a lot about the source code, but they can't validate incorrect algorythm. Pust is also very strict language, but
it sucks, and it's unreadable pile of characters. Remember, no matter how strict language you use, it'll never validate correctness of the algorythm, only syntax mistakes and
few other checks like life-times, bounds, etc. I'll mention this a lot, think twice, write once.

Obedient servants:
$ gcc -Wall
$ clang -Wall

Complicated servants:
$ gcc -ansi -Werror -Wall -Wextra -Wpedantic
$ clang -ansi -Werror -Weverything

Terrible servants (same as above, but with also using):
$ splint [custom flags]
$ valgrind --show-leak-kinds=all --leak-check=full
*/

char * string_realign (char * string, int amount, char character) { // Now, this is our "align string to right" function, lets explain it.
int offset, length; // We're declaring two local (automatic) variables of type 'int'.

length = string_length (string);
length = string_length (string); // We'll use variable 'length' later in the code, so we initialize it to length of the string.

for (offset = 0; offset != length; ++offset) {
string [amount - offset - 1] = string [length - offset - 1];
for (offset = 0; offset != length; ++offset) { // We're essentially moving the string to the right, iterating through its' length to amount.
string [amount - offset - 1] = string [length - offset - 1]; // Needless to say, string needs to have enough memory ((pre) allocated) for it to store it.
}

for (offset = 0; offset != amount - length; ++offset) {
string [offset] = character;
for (offset = 0; offset != amount - length; ++offset) { // Now, we have some "garbage" data left from the actual string, so we iterate through left side and:
string [offset] = character; // Assign to it argument 'character' that we provided in a function call. We can align with anything.
}

string [amount] = '\0';
string [amount] = CHARACTER_NULL; // I like to null terminate them explicitly, so I don't have to worry about tiny bugs later.

return (string);
return (string); // Lastly, we return a pointer to our modified string, in order to, again, bind function calls.
}

/*
Again, please consider these 'terminal_*' functions black magic, as well as 'number_to_string' and 'format_to_string' as they are more complex to cover them at this point, we'll
talk more about them later... For now, just take a look at how I format the code in them.
*/

void terminal_clear (void) {
echo ("\033[2J\033[H");
}
@@ -344,12 +380,12 @@ char * number_to_string (int number) {
static char string [32];

for (i = 0; i != 32; ++i) {
string [i] = '\0';
string [i] = CHARACTER_NULL;
}

if (number == 0) {
string [0] = '0';
string [1] = '\0';
string [1] = CHARACTER_NULL;
return (string);
}

@@ -370,7 +406,7 @@ char * number_to_string (int number) {
++i;
}

string [i] = '\0';
string [i] = CHARACTER_NULL;

string_reverse (string);

@@ -383,12 +419,12 @@ char * format_to_string (int number, int sign, int base, int amount, char charac
static char string [32];

for (i = 0; i != 32; ++i) {
string [i] = '\0';
string [i] = CHARACTER_NULL;
}

if (number == 0) {
string [0] = '0';
string [1] = '\0';
string [1] = CHARACTER_NULL;

string_realign (string, amount, character);

@@ -409,7 +445,7 @@ char * format_to_string (int number, int sign, int base, int amount, char charac
++i;
}

string [i] = '\0';
string [i] = CHARACTER_NULL;

string_reverse (string);



+ 12
- 7
chapters/chapter_0.h Прегледај датотеку

@@ -90,7 +90,9 @@ C has mixed them in keywords, and most standard library headers mix them too...
- Headers: string memory limits time complex threads / stdio ctype 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 about talking how bad it is for readability... But lets ignore that for now and focus on code formatting.
About that, I don't even know where to begin about talking how bad it is for readability... But lets ignore that for now and focus on code formatting. Text you see above this
paragraph is enough to get you started, and text below is just expanding a little more on common sense when you're formatting your code. For example, how to align consequtive
external or internal function or variable declarations, how to align if statement condition(s) or switch statement body, and more.

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.
@@ -107,7 +109,8 @@ extern int32_t string_copy (char * string_a,
extern size_t copy_string_n (
string_t a,
string_t b,
size_t n);
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
@@ -214,13 +217,15 @@ extern char * string_copy_limit (char * string_0, char * string_1, int li
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 char * string_realign (char * string, int amount, char character); // This is a simple function that realigns a string to right, we'll use it way later ahead.

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);
// In chapter two, we'll explain ASCII escape sequences, for now, consider this to be some black magic.
extern void terminal_clear (void); // Offset and clear terminal screen output.
extern void terminal_colour (int colour, int effect); // Set terminal character attributes.
extern void terminal_cancel (void); // Reset terminal character attributes.
extern void terminal_show_cursor (int show); // Toggle rendering of terminal cursor.

// These will be useful in chapter three, where we'll learn about 'printf' function. It's too complex to cover it at this point.
extern char * number_to_string (int number);
extern char * format_to_string (int number, int sign, int base, int amount, char character);



+ 3
- 3
chapters/chapter_2.c Прегледај датотеку

@@ -455,7 +455,7 @@ int curses_render_number (int number, int colour, int effect, int x, int y) { //
return (curses_render_string (number_to_string (number), colour, effect, x, y));
}

int curses_render_string_limit (char * string, int limit, int colour, int effect, int x, int y) {
int curses_render_string_limit (char * string, int limit, int colour, int effect, int x, int y) { // This uses short "fix" for blank characters, but we'll align them better later.
int offset;

for (offset = 0; offset != limit; ++offset) {
@@ -473,8 +473,8 @@ int curses_render_string_limit (char * string, int limit, int colour, int effect
return (limit);
}

int curses_render_number_limit (int number, int limit, int colour, int effect, int x, int y) {
return (curses_render_string (format_to_string (number, 1, 10, limit, ' '), colour, effect, x, y));
int curses_render_number_limit (int number, int limit, int colour, int effect, int x, int y) { // Finally, this will align the number to the right and limit it as well.
return (curses_render_string_limit (number_to_string (number), limit, colour, effect, x, y));
}

#endif

+ 3
- 5
chapters/chapter_2.h Прегледај датотеку

@@ -9,11 +9,6 @@ It is distributed in the hope that it will be useful or harmful, it really depen
#ifndef CHAPTER_2_HEADER
#define CHAPTER_2_HEADER

/*
This is probably the first program new programmers write in language they're learning. It simply prints text to standard output. As C is very old programming language, you have a
lot of ways to do it, so we'll simply put all of them into array of function pointers, and call them sequentially in loop in our main function.
*/

#include <stdio.h> // We need this header file for functions 'puts' and 'printf'.
#include <unistd.h> // And in this header file we have write system call.

@@ -61,6 +56,9 @@ Now, lets talk very briefly about what's wrong with 'PLEASE_NO':
- Last one is tricky, you should name function agruments in function declarations, but some linters will warn you not to do it, since some compiler don't check them.

Very soon, you'll be able to write your own small C programs, so prepare for it.

This is probably the first program new programmers write in language they're learning. It simply prints text to standard output. As C is very old programming language, you have a
lot of ways to do it, so we'll simply put all of them into array of function pointers, and call them sequentially in loop in our main function.
*/

extern void hello_world_0 (void); // All 4 functions take no agruments, and return nothing. They just execute the code that's defined in them.


+ 11
- 0
xhartae.c Прегледај датотеку

@@ -32,6 +32,17 @@ We're dealing with a low-level functional (and procedural) programming language
to sail on it after some practice. This will never be a book. It has no readers. It's not even printed. It's pages are files. It's cover is a folder. This will never be a book. I,
for the most part, am having fun writing this, same as I have fun while programming. You won't get a job after reading this "book", only some knowledge.

How to read this book?

- First of all, read the "README.md" file in base directory. Run scripts there in the order they're listed.
- Now, make a copy of 'xhartae' folder somewhere, and run '$ xhartae' from there, or just read the source.
- Feel free to modify (edit) that copy, if you can't fix some error, just replace it with the original one.

When you read some book about a programming language, you can't modify it and recompile it. You can do it with this book, so it's not really a "book", but at the same time it is.
If you fuck up something and don't know how to fix it, you'll easily replace that folder with the working one, which you can also download from my GitLain repository. If you're,
for example, learning about switch statement, you can just write it inside this book, recompile it and run it. If compiler spits out warnings or error that you can't fix, just
delete that part of the code, and go on with your life...

Why should you learn or use C programming language in 2023?

- C was inspiration for many newer programming languages for good reasons.


Loading…
Откажи
Сачувај