Bläddra i källkod

Changed header file including, added more comments...

master
Ognjen Milan Robovic 5 månader sedan
förälder
incheckning
2286ad75dd
13 ändrade filer med 180 tillägg och 57 borttagningar
  1. +3
    -0
      chapter/chapter_0.c
  2. +38
    -14
      chapter/chapter_0.h
  3. +20
    -8
      chapter/chapter_1.c
  4. +11
    -1
      chapter/chapter_1.h
  5. +10
    -0
      chapter/chapter_2.c
  6. +12
    -11
      chapter/chapter_2.h
  7. +3
    -0
      chapter/chapter_3.c
  8. +9
    -2
      chapter/chapter_3.h
  9. +42
    -14
      chapter/chapter_4.c
  10. +23
    -5
      chapter/chapter_4.h
  11. +3
    -0
      chapter/chapter_x.c
  12. +2
    -0
      chapter/chapter_y.c
  13. +4
    -2
      xhartae.c

+ 3
- 0
chapter/chapter_0.c Visa fil

@@ -1,6 +1,9 @@
#ifndef CHAPTER_0_SOURCE // These two, and "#endif" at the end of the file are header guards, we'll talk about them more when the time comes!
#define CHAPTER_0_SOURCE

#include <stdlib.h> // We'll need this header file for malloc, calloc, realloc, free, atexit, rand and exit (some will be used in future chapters).
#include <unistd.h> // And this one for read and write.

#include "chapter_0.h" // We're pasting macros, enumerations and function declarations from header file "chapter_0.h" into this file, at this location.

/*


+ 38
- 14
chapter/chapter_0.h Visa fil

@@ -1,12 +1,15 @@
#ifndef CHAPTER_0_HEADER
#define CHAPTER_0_HEADER

#include <stdlib.h> // We'll need this header file for malloc, calloc, realloc, free, atexit, rand and exit (some will be used in future chapters).
#include <fcntl.h> // This one for open and O_ flags.
#include <unistd.h> // And this one for read, write, close and lseek.

/*
Code formatting
In this chapter, you'll learn about:

- Code formatting
- Operators
- Function and variable declarations
- Enumerations
- Some basic functions
- String and memory functions

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
@@ -163,7 +166,7 @@ int main (void) {
int32_t main (int32_t argc,
char * argv []) {

// Somewhere before with using 'typedef':
// Somewhere before, with using 'typedef':
// typedef int number_t;
// typedef char * string_t;
number_t main (
@@ -173,17 +176,36 @@ number_t main (

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.

Also, what is keyword 'enum' for? It's for enumerations, and early C programming language didn't have it. It assigns a value to some identifier, if not specified, it's automatic:

@C
// Values of A, B and C are same for these 3 enumerations.
enum { A, B, C };
enum { A = 0, B = 1, C };
enum { A = 0, B = 1, C = 2 };
// However, if you use:
enum { A = 1, B, C };
// Then, A is 1, B is 2 and C is 3. Easy, right? Also:
enum { A, B, C = 0, D };
// In this last case, A and C are 0, B and D are 1.
@

By default, it always starts from zero, if you assign some value to it (must be integer), next one will be increment of previous value, if otherwise not specified.
*/

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,
TRUE
};

enum { // I use these to explicitly identify character literals outside of strings.
// 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.
// I align them like this, you can do whatever you want here, I just don't like to write a lot of short lines of code... I align long identifiers by 40 characters + indentation.
// 8 + 0 * 40 8 + 1 * 40 8 + 2 * 40 8 + 3 * 40
enum {
// I use these to explicitly identify character literals outside of strings.
// 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.
// I align them like this, you can do whatever you want here, I just don't like to write a lot of short lines of code...
// I align long identifiers by 40 characters + indentation width (denoted with T). I won't align next two comments, to show you the offset.
// T + 0 * 40 T + 1 * 40 T + 2 * 40 T + 3 * 40
// ^ ^ ^ ^
CHARACTER_NULL, CHARACTER_START_HEADER, CHARACTER_START_TEXT, CHARACTER_END_TEXT,
CHARACTER_END_TRANSMISSION, CHARACTER_ENQUIRY, CHARACTER_ACKNOWLEDGE, CHARACTER_BELL,
@@ -196,12 +218,14 @@ enum { // I use these to explicitly identify character literals outside of strin
CHARACTER_COUNT // Not an actual ASCII table count (128), but for ending special invisible characters.
};

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, look above...
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, look above...
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. In some cases, order matters!
enum {
// Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays. In some cases, order matters!
COLOUR_GREY, COLOUR_RED, COLOUR_GREEN, COLOUR_YELLOW, COLOUR_BLUE, COLOUR_PINK, COLOUR_CYAN, COLOUR_WHITE,
COLOUR_COUNT
};
@@ -229,7 +253,7 @@ extern char * string_reverse (char * string); // Notice
extern int string_compare_limit (char * destination, char * source, int limit); // These ones too, it's beautiful (in my opinion), tho some consider it useless.
extern char * string_copy_limit (char * destination, char * source, int limit);
extern char * string_concatenate_limit (char * destination, char * source, 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_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); // This is a simple function that realigns a string to right, we'll use it way later ahead.



+ 20
- 8
chapter/chapter_1.c Visa fil

@@ -1,6 +1,10 @@
#ifndef CHAPTER_1_SOURCE
#define CHAPTER_1_SOURCE

#include <stdlib.h> // We'll need this header file for malloc, calloc, realloc, free, atexit, rand and exit (some will be used in future chapters).
#include <fcntl.h> // This one for open and 'O_' flags.
#include <unistd.h> // And this one for read, write, close and lseek.

#include "chapter_1.h" // Get used to this... We're pasting macros, enumerations and function declarations again...

int character_is_uppercase (char character) { // Returns a boolean value, aka FALSE or TRUE, aka 0 or 1...
@@ -65,7 +69,8 @@ int character_is_hexadecimal (char character) { // Same as function 'character_i
/*
Now, we can see how function 'character_compare_array' was implemented, but know that it could be even shorter, like you see below. However, I really think it's for the best to
use curly and round braces, when even the compiler won't warn about them. You can easily see the scope of something if you have a text editor capable of highlighting matching
braces, and almost all of them have that feature.
braces, and almost all of them have that feature. Also, don't be afraid of longer lines of code. You can even enable word-wrapping in your ed text editor running on Commodore 64
with 128 GiB of RAM. Just focus more on what you're doing, don't limit yourself to mere 80 characters per line.

@C
int character_compare_array (char character, char * character_array) {
@@ -99,13 +104,14 @@ few important ones down below with some copy & paste magic, but I'll keep it sho
#include <sys/stat.h> // Core something, I don't even know...
#include <fcntl.h> // Few system calls.

int open (const char *pathname, int flags);
int open (const char *pathname, int flags, mode_t mode);
int creat (const char *pathname, mode_t mode);
int openat (int dirfd, const char *pathname, int flags);
int openat (int dirfd, const char *pathname, int flags, mode_t mode);
int open (const char * pathname, int flags );
int open (const char * pathname, int flags, mode_t mode);
int creat (const char * pathname, mode_t mode);

int openat (int dirfd, const char * pathname, int flags );
int openat (int dirfd, const char * pathname, int flags, mode_t mode);

// Flags (modes, one of the first three must always be present in mode mask):
// Some commonly used file flags (modes, one of the first three must always be present in mode mask):
// - O_RDONLY: Open or create file as 'read only', prohibit writing to that file.
// - O_WRONLY: Open or create file as 'write only', so you have permission to modify it.
// - O_RDWR: Open or create file as 'read and write', so you can do whatever you want with it...
@@ -129,6 +135,8 @@ int file_open (char * name, int mode) {
// Or align it to break two longer function arguments:
// fatal_failure ((descriptor = open (name, mode)) == -1,
// "file_open: Failed to open file, function open returned invalid descriptor.");
// As you can see, if you want to inline variable assignment, you must use braces, like I did in uncommented example.
// And don't confuse '==' equality comparison and '=' assignment operators!

return (descriptor); // Return opened file descriptor.
}
@@ -219,6 +227,10 @@ void * file_record (char * name) {
return (data); // We return pointer to new memory, but remember, we have to free it later.
}

/*
I won't cover next two functions at this point, because they might be harder to understand, but if you feel confident, try to guess what they do...
*/

char * number_to_string (int number) {
int i, sign;

@@ -299,7 +311,7 @@ char * format_to_string (int number, int sign, int base, int amount, char charac
return (string);
}

int randomize (int minimum, int maximum) {
int randomize (int minimum, int maximum) { // Now, we're simply returning random integer between 'minimum' and 'maximum', inclusively.
return (rand () % (maximum - minimum + 1) + minimum);
}



+ 11
- 1
chapter/chapter_1.h Visa fil

@@ -4,6 +4,15 @@
#include "chapter_0.h" // We need this header file for some core enumeration definitions and function declarations.

/*
In this chapter, you'll learn about:

- Keywords
- Normal identifiers
- Types
- Character functions
- File functions
- ASCII table

Now that you've read the chapter zero, we should get into some technical details about C programming language. This will be the most imporant chapter for people who know some
other lower level programming language, or who intuitively understand "building blocks" of some system. Below is just a simple matrix of them, 8 x 4, so you can see that there are
really 32 keywords (ANSI C standard, I dislike newer standards), and even more below we'll categorize them. Also, keep in mind that I'll briefly talk about other C standards such
@@ -107,7 +116,8 @@ need to know exactly what you're doing and what your code will do in order to ha
a lot of types, since it's completely different language and has different coding practices.
*/

enum { // We won't even cover all of those file formats, this is just an example of how to do similar task without hardcoding file extensions, we'll use it later.
enum {
// We won't even cover all of those file formats, this is just an example of how to do similar task without hardcoding file extensions, we'll use it later.
FILE_TYPE_TEXT, FILE_TYPE_COMMON_ASSEMBLY, FILE_TYPE_FLAT_ASSEMBLY, FILE_TYPE_GNU_ASSEMBLY,
FILE_TYPE_NETWIDE_ASSEMBLY, FILE_TYPE_YET_ANOTHER_ASSEMBLY, FILE_TYPE_C_SOURCE, FILE_TYPE_C_HEADER,
FILE_TYPE_ADA_BODY, FILE_TYPE_ADA_SPECIFICATION, FILE_TYPE_CPP_SOURCE, FILE_TYPE_CPP_HEADER,


+ 10
- 0
chapter/chapter_2.c Visa fil

@@ -1,8 +1,18 @@
#ifndef CHAPTER_2_SOURCE
#define CHAPTER_2_SOURCE

#include <stdlib.h>
#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_2.h" // We're copying function and variable declarations from this file here. This shouldn't be copied twice, more on that later...

#define CURSES_FORMAT ((int) sizeof ("\033[-;3-m-\033[0m") - 1) // We'll use these three macros through-out cursed functions.
#define CURSES_REVERT ((int) sizeof ("\033[H") - 1)
#define CURSES_CURSOR ((int) sizeof ("\033[---;---H") - 1)

/*
Function 'hello_world_0' uses (rougly said) a system call instead of a function, but I don't even know what will different compilers do to that line of code. What's a system call?
Well, when you're writing assembly, you have some general purpose registers, on mine and your machine, there's 16 of them, and you move some data in them, then use 'syscall'


+ 12
- 11
chapter/chapter_2.h Visa fil

@@ -5,6 +5,15 @@
#include <unistd.h> // And in this header file we have write system call.

/*
In this chapter, you'll learn about:

- Curses library (libncurses "clone")
- More on function declarations
- General scope
- Escape sequences
- Sane program layout
- Terminal input and output

Lets talk about function declaration. In C, sometimes you need to declare functions that you'll use before they're called. I prefer to always declare functions except when I'm
quickly prototyping something out. Function declarations are property of old programming languages, you don't have to use them if you're calling every function after it's defined
(but not declared, there's a difference), but if that function is only used in one file, you should use 'static' keyword like in the example below. Keyword 'extern' tells the
@@ -70,11 +79,6 @@ teletypewriters, terminal was obscure magic. Nowdays, parents scare their childr
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"

@@ -88,11 +92,8 @@ you won't be able to see icons, you won't pass the Login text on your screen, yo
#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.
#define CURSES_REVERT ((int) sizeof ("\033[H") - 1)
#define CURSES_CURSOR ((int) sizeof ("\033[---;---H") - 1)

enum { // This enumeration will be used for signal processing.
enum {
// This enumeration will be used for signal processing, I put some special cases on their own line.
SIGNAL_NONE,
SIGNAL_ANY,
SIGNAL_A, SIGNAL_B, SIGNAL_C, SIGNAL_D, SIGNAL_E, SIGNAL_F, SIGNAL_G, SIGNAL_H,
@@ -142,7 +143,7 @@ Effects:
- Cyan: 6
- White: 7

Instead of hardcoding values yourself and remembering those, you can just use enumerations from "chapter_0.h", like, COLOUR_BLUE and EFFECT_BOLD.
Instead of hardcoding values yourself and remembering those, you can just use enumeration identifiers, like, COLOUR_BLUE and EFFECT_BOLD.
*/

extern int curses_character; // Literal character (integer) that user has pressed, some of them are more than single byte, like arrow keys defined above.


+ 3
- 0
chapter/chapter_3.c Visa fil

@@ -1,6 +1,9 @@
#ifndef CHAPTER_3_SOURCE
#define CHAPTER_3_SOURCE

#include <stddef.h>
#include <stdarg.h>

#include "chapter_3.h"

/*


+ 9
- 2
chapter/chapter_3.h Visa fil

@@ -1,12 +1,19 @@
#ifndef CHAPTER_3_HEADER
#define CHAPTER_3_HEADER

#include <stdarg.h>

#include "chapter_0.h"
#include "chapter_1.h"

/*
In this chapter, you'll learn about:

- Variadic argument functions
- Basic 'printf' functionality
- Type safety
- More on function pointers
- Control flow switching
- Escape characters

Now, time has come to talk about (sadly) the most important standard library function in C programming language. Function 'printf' is like some semi-drunk old man, stumbling on
the streets, talking to himself, talking to other people who try to ignore him, but if you stand and talk to him, he'll sometimes start talking about random things, and sometimes
he'll stay on-topic. So, what does function 'printf' do? Essentially, it'll print formatted string to standard output, formatted in this case means that in the main string (first


+ 42
- 14
chapter/chapter_4.c Visa fil

@@ -1,6 +1,8 @@
#ifndef CHAPTER_4_SOURCE
#define CHAPTER_4_SOURCE

#include <stdlib.h>

#include "chapter_4.h"

/*
@@ -46,14 +48,14 @@ about our character and string matching and 'syntax_select' to process our text
'syntax_select', will return index of the syntax rule that matches to our offset in string and store size of the match in 'length' variable, we'll look into it.
*/

static int syntax_count = 0; // Number of previously defined syntax rules.
static int * syntax_enrange = NULL; // Syntax rule can start with any character from 'syntax_begin' if this value is TRUE.
static int * syntax_derange = NULL; // Syntax rule can start with any character from 'syntax_end' if this value is TRUE.
static char * * syntax_begin = NULL; // Strings containing valid character (sub)sequence for begining the scan.
static char * * syntax_end = NULL; // Strings containing valid character (sub)sequence for ending the scan.
static char * syntax_escape = NULL; // Escape sequence for the rule, useful for line-breaks in C macros and line-based languages.
static int * syntax_colour = NULL; // Colour for our token, these two could be completely independent, but I like to keep them here.
static int * syntax_effect = NULL; // Effect for our token.
static int syntax_count = 0; // Number of previously defined syntax rules.
static int * syntax_enrange = NULL; // Syntax rule can start with any character from 'syntax_begin' if this value is TRUE.
static int * syntax_derange = NULL; // Syntax rule can start with any character from 'syntax_end' if this value is TRUE.
static char * * syntax_begin = NULL; // Strings containing valid character (sub)sequence for begining the scan.
static char * * syntax_end = NULL; // Strings containing valid character (sub)sequence for ending the scan.
static char * syntax_escape = NULL; // Escape sequence for the rule, useful for line-breaks in C macros and line-based languages.
static int * syntax_colour = NULL; // Colour for our token, these two could be completely independent, but I like to keep them here.
static int * syntax_effect = NULL; // Effect for our token.

/*
Lets go in more details about how this function works. Standard library function 'atexit' will take as an argument function pointer of form 'extern void name (void)' that will,
@@ -67,7 +69,7 @@ when 'syntax_active' is FALSE, we'll change it to true, so 'atexit' won't be exe
we're just deallocating (freeing) the memory, so we don't leak it and generate Valgrind warnings.
*/

static void syntax_delete (void) {
static void syntax_delete (void) { // We want to free used resources at certain point in our program, so we can declare this function as internal with 'static' keyword.
int offset;

if (syntax_count == 0) { // If syntax "library" wasn't used, we don't want to deallocate memory, we just return.
@@ -102,6 +104,7 @@ In 'syntax_define' function we're reallocating (enlarging) memory, effectively a
be used with 'syntax_select' function to make our syntax highlighting. Lets explain what those function arguments do:

@C
// To see how I use it, look at 'syntax_highlight_*' functions below.
int syntax_define (int enrange, // Strict matching of string 'begin' in buffer range if FALSE, any character matching if TRUE.
int derange, // Strict matching of string 'end' in buffer range if FALSE, and again, any character matching if TRUE.
char * begin, // String of array of characters to begin matching.
@@ -146,7 +149,10 @@ int syntax_define (int enrange, int derange, char * begin, char * end, char esca
}

/*
This is more complex, but if you use your eyes to look, your brain to comprehend and your heart to love, I'm sure that you'll understand it.
This is more complex, but if you use your eyes to look, your brain to comprehend and your heart to love, I'm sure that you'll understand it. Essentially, we are at some point in
our text file (we're using pointer to type 'char' to indicate where that is), we try to match characters from that point onward with our previously defined syntax rules, either
strictly, but using entire string (for keywords) or any character inside it (for numbers, identifiers, etc.). If we found it, we check next character depending on 'syntax_derange'
and either finish first loop, or continue. After, we need to know the length of our matched syntax rule, that's it.
*/

int syntax_select (char * string, int * length) {
@@ -186,9 +192,9 @@ int syntax_select (char * string, int * length) {
} // And now we have our 'select' value.

// If there was no syntax rule detected, we need to return from a function, and increment the offset by setting variable 'length' to 1. If we don't increment it, at the
// first unrecognized character, our second nested-loop inside function 'syntax_render_file' would use uninitialized or zero value, depending on how we structured our code
// before that. We also return 'syntax_count' as the syntax rule index, which is invalid, and would produce Valgrind warning if we didn't handle it. In my unimportant
// opinion, this if statement is the ugliest part of the function.
// first unrecognized character, our second nested-loop inside function 'program_curses_view_file' would use uninitialized or zero value, depending on how we structured
// our code before that. We also return 'syntax_count' as the syntax rule index, which is invalid, and would produce Valgrind warning if we didn't handle it. In my
// unimportant opinion, this if statement is the ugliest part of the function.

if (select >= syntax_count) { // If we didn't found our string, return.
* length = 1;
@@ -275,6 +281,27 @@ void syntax_highlight_c (void) {
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
}

/*
Now, why the hell am I talking about Ada programming language again? Well, you see...

Ada programming language was made in 1980, it was designed around the ideas of procedural programming, strict type safety and readability. As I mentioned before, the way I write C
comes from the way I write Ada (in some cases, not always, as they are quite different languages). For example, you can see that Ada has more keywords and less operators than C,
and is very strict language, while C is loose. Why is that interesting? Because Ada can interface with libraries written in C, and we'll use that in later chapters. You can spot
how different they are, and still, you can write your project mixing those languages. That's the true power of C.

I'll very briefly comment out what we're using in Ada, so you can see and compare syntax of C and Ada, and here's an example below:

@Ada
with ada.text_io; -- Our <stdio.h> in Ada basically.
use ada.text_io; -- With this, we're automatically enabling a namespace.

procedure hello_world is -- In C, this is 'extern void main (void)' so to say...
begin -- This is Ada's way of saying '{'.
put_line ("Hello " & "world!"); -- We're concatenating 2 strings and printing them.
end hello_world; -- And this is Ada's way of saying '}'.
@
*/

void syntax_highlight_ada (void) {
char * separators = ".,:;<=>#+*-/&|()'\" \t\r\n";

@@ -314,7 +341,7 @@ void syntax_highlight_ada (void) {
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
}

void syntax_render_file (char * text_file, int x, int y) {
void program_curses_view_file (char * text_file, int x, int y) {
char * text_data; // This local variable will hold our data.

int reset_x, reset_y; // Since we're using curses, we want to reset the offset.
@@ -360,6 +387,7 @@ void syntax_render_file (char * text_file, int x, int y) {
// Or, if you find this more intuitive:
// colour = (select < syntax_count) ? syntax_colour [select] : COLOUR_WHITE;
// effect = (select < syntax_count) ? syntax_effect [select] : EFFECT_NORMAL;
// And I don't really care for negative values, but feel free to check for them, as they aren't even returned normally.

if (select >= syntax_count) { // Here, we're handling error value of 'syntax_select'.
colour = COLOUR_WHITE;


+ 23
- 5
chapter/chapter_4.h Visa fil

@@ -7,6 +7,15 @@
#include "chapter_3.h"

/*
In this chapter, you'll learn about:

- Programming language layout
- Syntax highlighting
- Importance of readability
- Differences between languages
- More on memory management
- Using curses

I believe that this chapter should be a breakpoint for you to write a simple C program. So far, we've learned in:

- chapter 0: To format our code properly in order to increase readability and we've implemented some core functions for memory management, strings and input / output.
@@ -19,7 +28,7 @@ example, some of them will require functions from some or all previous chapter s
chapters. Instead of that, we'll (re)implement newer stuff with different approach if necessary. That way, you can be sure that if you're reading chapter four, for example, it'll
only use functions and variables defined in chapters zero to three. Lets begin.

I'll write this huge 'syntax_render_file' function in somewhat procedural style of programming, so to say, and in the next chapter, we'll use more modular way, using many more
I'll write this huge 'program_curses_view_file' function in somewhat procedural style of programming, so to say, and in the next chapter, we'll use more modular way, using many more
functions. Learning anything, including the C programming language, is like a journey. Maybe you think it won't last long, and it ends up being quite long journey, or maybe you
think it'll be very long, that you'll walk miles and miles, and it ends up being short (you rage-quit). The final destination you're going towards always depends on where you
left-off and where you're coming from. For example, if you wrote Ada, you'll like chapter four, if you wrote C++, you'll like chapter five.
@@ -34,7 +43,9 @@ I'll also list a few "traps" right here, where most programmers get caught in:
First of all, there are a lot of standards, people who don't have more important work to do make those. There are a lot of CPU architectures, x86-64 being used a lot, then ISA
(instruction set architecture) such as CISC, RISC, MISC, OISC, and even more things that should't matter for you like SIMD, AVX, ST, MMX, XMM, YMM, ZMM, et fucking cetera. Then,
we have many many GPU hardware, they each have some part of their own ISA, writing direct code for one GPU won't work on other GPUs, so we need to use OpenGL, Vulkan or Direct3D.
Do you see where this is going, adding complexity on top of complexity, abstracting the abstractions, due to standardization.
Do you see where this is going, adding complexity on top of complexity, abstracting the abstractions, due to standardization. Then again, we have many programming languages, some
of them have multiple standards, like C, C++, Ada, Fortran, basically, popular programming languages. For some of those languages, there are multiple compilers, and sometimes they
support language extensions that aren't the part of the core language. That's why nothing is truly portable.

If every company make their own standard, thinking they're smartest, there's no standardization. Just look at the mirror, at your PC, laptop, whatever, then take a look outside
the window, and say out loud "My program will be written in C, it will run on 64-bit CPUs, it will depend only on Vulkan API, it will use XCB for display.". Take a deep breath,
@@ -45,14 +56,21 @@ Keep in mind that I don't work for any programming related company and I want to
hear me out, if 1000 people with some CS degree wrote a simple C program, all of those would look very similar. That's because they've been programmed into that line of thinking,
which is dangerous in my opinion for one reason: They think they're always right. I learned a lot from talking with smart people, some of them have CS degree, some not, so I don't
own what I know, no one owns anyones' knowledge, but they weren't always right. So, if you don't have a CS degree, you can learn C easier, that's my point.

C is good programming language to learn first because it shows you what can you create with very simple tools. Now, lets get to syntax highlighting:
*/

extern int syntax_define (int enrange, int derange, char * begin, char * end, char escape, int colour, int effect);
extern int syntax_select (char * string, int * length);
extern int syntax_define (int enrange, int derange, char * begin, char * end, char escape, int colour, int effect); // This must be called before 'syntax_select' function.
extern int syntax_select (char * string, int * length); // And we're not dealing with null-terminated strings here.

// Internally use 'syntax_define' to make C (and Ada below) syntax highlighting, it will use global variables internal to 'chapter_4.c' file.
// Worth noting:
// - We'll only have one "predefined syntax highlighting" per file type, because we don't want them to clash with each other.
// - We could use several syntax highlighting rules if we made one more level of arrays for all those global variables, and a rule to switch between them.
// - If you want to add support for some other language, you can try to make, for example 'syntax_highlight_python', it'll be a good exercise.
extern void syntax_highlight_c (void);
extern void syntax_highlight_ada (void);

extern void syntax_render_file (char * text_file, int x, int y);
extern void program_curses_view_file (char * text_file, int x, int y); // This is our subprogram that'll view some textual file in terminal, using our curses "library".

#endif

+ 3
- 0
chapter/chapter_x.c Visa fil

@@ -1,6 +1,9 @@
#ifndef CHAPTER_X_SOURCE
#define CHAPTER_X_SOURCE

#include <stdlib.h>
#include <stdarg.h>

#include "chapter_x.h"

/*


+ 2
- 0
chapter/chapter_y.c Visa fil

@@ -1,6 +1,8 @@
#ifndef CHAPTER_Y_SOURCE
#define CHAPTER_Y_SOURCE

#include <stdlib.h>

#include "chapter_y.h"

#define UNUSED(variable) (void) variable


+ 4
- 2
xhartae.c Visa fil

@@ -1,3 +1,5 @@
#include <stdlib.h>

#ifdef STATIC_SOURCE
#include "chapter/chapter_0.c"
#include "chapter/chapter_1.c"
@@ -125,7 +127,7 @@ int main (int argc, char * * argv) {
(void) argc;
(void) argv;

syntax_render_file ("program/program_1.c", 0, 0);
program_curses_view_file ("program/program_1.c", 0, 0);

blesses_configure ();

@@ -135,7 +137,7 @@ int main (int argc, char * * argv) {
blesses_synchronize ();
}

syntax_render_file ("example/ada.adb", 0, 0);
program_curses_view_file ("example/ada.adb", 0, 0);

return (EXIT_SUCCESS);
}

Laddar…
Avbryt
Spara