|
@@ -50,51 +50,71 @@ static void echo_one_by_one (int number) { |
|
|
default: break; |
|
|
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 |
|
|
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 |
|
|
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. |
|
|
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_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) { // We use character '%' this time, same as 'printf' function does, lets see... |
|
|
|
|
|
switch (format_id) { |
|
|
|
|
|
|
|
|
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 '%': { |
|
|
case '%': { |
|
|
out ("%", 1); |
|
|
|
|
|
|
|
|
printing_crossroad ("%", 1, file, string); |
|
|
} break; |
|
|
} break; |
|
|
case 'i': { |
|
|
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. |
|
|
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; |
|
|
} break; |
|
|
case 'f': { |
|
|
case 'f': { |
|
|
double ieee754; // Because we used curly braces, we can declare local variables in these blocks of code. |
|
|
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'. |
|
|
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; |
|
|
} break; |
|
|
case 's': { |
|
|
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; |
|
|
} break; |
|
|
default: { |
|
|
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; |
|
|
} 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. |
|
|
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. |
|
|
if (format [offset] == '/') { // Colouring special character is '/', and colours are specified from '0'...'7', and '-' to cancel them. |
|
|
++offset; |
|
|
++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! |
|
|
} else if (format [offset] == '%') { // And formatting special character is '%', it'll use variadic arguments! |
|
|
++offset; |
|
|
++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 { |
|
|
} else { |
|
|
out (& format [offset], 1); // Not a special character? Okay, we'll just print them one by one. |
|
|
out (& format [offset], 1); // Not a special character? Okay, we'll just print them one by one. |
|
|
} |
|
|
} |
|
|