Pushing as an update, unfinished comments in chapter 3...

This commit is contained in:
Ognjen Milan Robovic 2023-11-13 11:58:31 -05:00
parent bbef2a609e
commit 17df8ad502
4 changed files with 67 additions and 36 deletions

View File

@ -50,51 +50,71 @@ static void echo_one_by_one (int number) {
default: break;
}
}
@
You can find situations in which fall-through cases are good, for example, they can be very useful when encoding some CPU instructions into machine code, but guess what? The
compiler will think you've made some kind of mistake, like that you forgot to break from those cases, and it'll warn you about it. I like to clean all compiler warnings (and some
linter warnings, if they're not totally brain-dead), so I just don't use them. I know, sounds stupid, but there's usually some other way to do it, and to get the same solution.
@
Since we have several methods for printing text, they use standard output (terminal), file descriptor and a string respectively, we could implement them in separate functions, use
function pointers or simply copy+paste bunch of code into lot of functions, and form a "function family". I'm using the simplest solution here, we have one general function, and
explicitly declaring where I want my data to be printed. Simple as that. Lets call it 'printing_crossroad' for fun.
*/
static void print_colour (char colour_id) { // We use "special" character '/' to use terminal colours.
switch (colour_id) {
case '/': out ("/", 1); break; // If we have literally typed "//" in our 'format' string, it'll just output "/".
case '0': terminal_colour (COLOUR_GREY, EFFECT_BOLD); break; // Making the use of our 'terminal_colour' function.
case '1': terminal_colour (COLOUR_RED, EFFECT_BOLD); break;
case '2': terminal_colour (COLOUR_GREEN, EFFECT_BOLD); break;
case '3': terminal_colour (COLOUR_YELLOW, EFFECT_BOLD); break;
case '4': terminal_colour (COLOUR_BLUE, EFFECT_BOLD); break;
case '5': terminal_colour (COLOUR_PINK, EFFECT_BOLD); break;
case '6': terminal_colour (COLOUR_CYAN, EFFECT_BOLD); break;
case '7': terminal_colour (COLOUR_WHITE, EFFECT_BOLD); break;
case '-': terminal_cancel (); break; // Making the use of our 'terminal_cancel' function, "/-" will end colouring.
default: out ("?", 1); break; // Now, if we provided some other character after "/", I like to make an intentional mismatch.
} // It's not such a big mistake to abort the program, since it's obvious that results are bad.
static void printing_crossroad (char * text, int size, int file, char * string) { // We pass a lot of arguments here, it makes things simpler below.
if (file > 0) { // We don't want to print to standard input, which is file descriptor of value 0.
file_write (file, text, size); // And we simply "output" our text of certain size to wanted location.
} else if (string != NULL) {
string_copy_limit (string, text, size);
} else {
out (text, size);
}
}
static void print_format (char format_id, va_list argument_list) { // We use character '%' this time, same as 'printf' function does, lets see...
switch (format_id) {
static void print_colour (char colour_id, int file, char * string) {
switch (colour_id) { // We use "special" character '/' to use terminal colours.
case '/': printing_crossroad ("/", 1, file, string); break; // If we have literally typed "//" in our 'format' string, it'll just output "/".
case '0': printing_crossroad ("\033[1;30m", 7, file, string); break; // Notice that we couldn't use function 'terminal_colour', it only uses standard output.
case '1': printing_crossroad ("\033[1;31m", 7, file, string); break; // Since we want to support file descriptors and strings, we use 'printing_crossroad'.
case '2': printing_crossroad ("\033[1;32m", 7, file, string); break;
case '3': printing_crossroad ("\033[1;33m", 7, file, string); break;
case '4': printing_crossroad ("\033[1;34m", 7, file, string); break;
case '5': printing_crossroad ("\033[1;35m", 7, file, string); break;
case '6': printing_crossroad ("\033[1;36m", 7, file, string); break;
case '7': printing_crossroad ("\033[1;37m", 7, file, string); break;
case '-': printing_crossroad ("\033[0m", 4, file, string); break;
default: printing_crossroad ("?", 1, file, string); break; // Now, if we provided some other character after "/", I like to make an intentional mismatch.
} // It's not such a big mistake to abort the program, since it's obvious that results are bad.
}
static void print_format (char format_id, va_list argument_list, int file, char * string) {
switch (format_id) { // We use character '%' this time, same as 'printf' function does, lets see...
case '%': {
out ("%", 1);
printing_crossroad ("%", 1, file, string);
} break;
case 'i': {
int integer; // Leave these local variables uninitialized (don't assign a value to them).
int integer; // Leave these local variables uninitialized (don't assign a value to them).
char * format;
int length;
integer = va_arg (argument_list, int); // Macro 'va_arg' will move argument from the list into our local variable, with the provided type.
echo (number_to_string (integer)); // You might get the feeling that this isn't type safe, and you'd be totally right.
length = string_length (format = number_to_string (integer));
printing_crossroad (format, length, file, string); // You might get the feeling that this isn't type safe, and you'd be totally right.
} break;
case 'f': {
double ieee754; // Because we used curly braces, we can declare local variables in these blocks of code.
ieee754 = va_arg (argument_list, double); // I intentionally call this IEEE754 because I hate to use 'float' and 'double'.
echo (number_to_string ((int) ieee754)); // And we're printing to terminal our (rounded) number.
char * format;
// And we're printing to terminal our (rounded) number.
format = number_to_string ((int) ieee754);
printing_crossroad (format, string_length (format), file, string);
} break;
case 's': {
char * string; // Really simple stuff, but needs some time getting used to it, we're writing in an old language.
string = va_arg (argument_list, char *); // In my opinion, this should be the part of the C language itself, not some macro black magic.
echo (string); // You can write a bunch of variadic functions yourself if you want, to easy your workflow in some cases.
char * literal; // Really simple stuff, but needs some time getting used to it, we're writing in an old language.
literal = va_arg (argument_list, char *); // In my opinion, this should be the part of the C language itself, not some macro black magic.
// You can write a bunch of variadic functions yourself if you want, to easy your workflow in some cases.
printing_crossroad (literal, string_length (literal), file, string);
} break;
default: {
out ("?", 1); // Again, I think it's best to print a bad thing, see it and fix it, then to abort the program in this case...
printing_crossroad ("?", 1, file, string); // Again, I think it's best to print a bad thing, see it and fix it, then to abort the program in this case...
} break;
}
@ -132,10 +152,10 @@ void print (char * format, ...) {
for (offset = 0; offset != length; ++offset) { // We start iterating through our 'format' string, and looking for special characters below.
if (format [offset] == '/') { // Colouring special character is '/', and colours are specified from '0'...'7', and '-' to cancel them.
++offset;
print_colour (format [offset]); // We're calling function that will colour our printed text, this one is simple.
print_colour (format [offset], 0, NULL); // We're calling function that will colour our printed text, this one is simple.
} else if (format [offset] == '%') { // And formatting special character is '%', it'll use variadic arguments!
++offset;
print_format (format [offset], argument_list); // We're calling function that will format our agruments, so we pass variable 'argument_list'.
print_format (format [offset], argument_list, 0, NULL); // We're calling function that will format our agruments, so we pass variable 'argument_list'.
} else {
out (& format [offset], 1); // Not a special character? Okay, we'll just print them one by one.
}

View File

@ -12,6 +12,7 @@ It is distributed in the hope that it will be useful or harmful, it really depen
#include <stdarg.h>
#include "chapter_0.h"
#include "chapter_1.h"
/*
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

View File

@ -13,4 +13,14 @@ gcc -g -Wall -Wextra -Wpedantic -O0 -c -o xhartae.o xhartae.c
gcc -o xhartae xhartae.o chapters/chapter_0.o chapters/chapter_1.o chapters/chapter_2.o chapters/chapter_3.o
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_0.h
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_0.c
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_1.h
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_1.c
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_2.h
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_2.c
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_3.h
splint -weak -warnposix -retvalother -syntax -type chapters/chapter_3.c
splint -weak -warnposix -retvalother -syntax -type xhartae.c
exit

View File

@ -6,16 +6,16 @@ And when you do redistribute it or modify it, it will use either version 3 of th
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 STATIC_SOURCE
#include "chapters/chapter_0.h"
#include "chapters/chapter_1.h"
#include "chapters/chapter_2.h"
#include "chapters/chapter_3.h"
#ifdef STATIC_SOURCE
#include "chapters/chapter_0.c"
#include "chapters/chapter_1.c"
#include "chapters/chapter_2.c"
#include "chapters/chapter_3.c"
#else
#include "chapters/chapter_0.c"
#include "chapters/chapter_1.c"
#include "chapters/chapter_2.c"
#include "chapters/chapter_3.c"
#include "chapters/chapter_0.h"
#include "chapters/chapter_1.h"
#include "chapters/chapter_2.h"
#include "chapters/chapter_3.h"
#endif
/*