From 17df8ad502f5165ba2303928e22749ee40f69d4a Mon Sep 17 00:00:00 2001 From: xolatile Date: Mon, 13 Nov 2023 11:58:31 -0500 Subject: [PATCH] Pushing as an update, unfinished comments in chapter 3... --- chapters/chapter_3.c | 74 +++++++++++++++++++++++++++++++++------------------- chapters/chapter_3.h | 1 + compile.sh | 10 +++++++ xhartae.c | 18 ++++++------- 4 files changed, 67 insertions(+), 36 deletions(-) diff --git a/chapters/chapter_3.c b/chapters/chapter_3.c index 9a86967..b4f8d13 100644 --- a/chapters/chapter_3.c +++ b/chapters/chapter_3.c @@ -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. } diff --git a/chapters/chapter_3.h b/chapters/chapter_3.h index e13f504..20c6e23 100644 --- a/chapters/chapter_3.h +++ b/chapters/chapter_3.h @@ -12,6 +12,7 @@ It is distributed in the hope that it will be useful or harmful, it really depen #include #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 diff --git a/compile.sh b/compile.sh index 02b59d5..f408ae5 100644 --- a/compile.sh +++ b/compile.sh @@ -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 diff --git a/xhartae.c b/xhartae.c index 44bcad1..8d553bb 100644 --- a/xhartae.c +++ b/xhartae.c @@ -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 /*