forked from xolatile/xhartae
Finished chapter 4, I will hunt grammar mistakes later...
This commit is contained in:
parent
715063ebc6
commit
2f4bc29217
@ -181,6 +181,7 @@ int string_compare (char * string_0, char * string_1) {
|
|||||||
return (FALSE); // > We return FALSE, 0, since strings aren't the same...
|
return (FALSE); // > We return FALSE, 0, since strings aren't the same...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (* string_0 != * string_1) { // Now, we'll do one last termination check.
|
if (* string_0 != * string_1) { // Now, we'll do one last termination check.
|
||||||
return (FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
|
@ -158,72 +158,80 @@ static int syntax_define (int enrange, int derange, char * begin, char * end, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: WE LEFT OF HERE...
|
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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int syntax_select (char * string, int * length) {
|
static int syntax_select (char * string, int * length) {
|
||||||
int offset, subset, select;
|
int offset, select;
|
||||||
|
|
||||||
fatal_failure (syntax_active == FALSE, "syntax_select: Syntax is not active.");
|
fatal_failure (syntax_active == FALSE, "syntax_select: Syntax is not active."); // Don't select without rules, abort!
|
||||||
fatal_failure (string == NULL, "syntax_select: String is null.");
|
fatal_failure (string == NULL, "syntax_select: String is null.");
|
||||||
fatal_failure (length == NULL, "syntax_select: Length is null.");
|
fatal_failure (length == NULL, "syntax_select: Length is null.");
|
||||||
|
|
||||||
for (select = offset = 0; select != syntax_count; ++select) {
|
// In this first part of the function, we need to check if our syntax rule has been detected at the string offset we've provided. We're looping defined syntax rules and
|
||||||
if (syntax_enrange [select] == FALSE) {
|
// choosing whether to compare any of the characters, or full string, depending on 'syntax_enrange' value which is essentially boolean, true or false, which I express with
|
||||||
if (string_compare_limit (string, syntax_begin [select], string_length (syntax_begin [select])) == TRUE) {
|
// 'int' type for "type-safety simplicity". Keep in mind that we're not returning or modifying the string we provided, so it won't be null-terminated, instead I think
|
||||||
break; // We need to limit our string comparisson function.
|
// it's best to modify only variable 'length', hence we check with 'string_compare_limit' function.
|
||||||
} else {
|
for (select = offset = 0; select != syntax_count; ++select) { // We're looping defined syntax rules:
|
||||||
continue;
|
if (syntax_enrange [select] == FALSE) { // Choosing the comparisson:
|
||||||
}
|
if (string_compare_limit (string, syntax_begin [select], string_length (syntax_begin [select])) == TRUE) { // Limiting our string comparisson.
|
||||||
} else {
|
break; // If strings are same, we exit the loop.
|
||||||
for (subset = 0; subset != string_length (syntax_begin [select]); ++subset) {
|
|
||||||
if (string [offset] == syntax_begin [select] [subset]) {
|
|
||||||
goto selected; // We can't use 'break' here, because it will exit only one loop, not both of them.
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else { // Else, we compare any character.
|
||||||
|
if (character_compare_array (string [offset], syntax_begin [select]) == TRUE) { // With our obviously named function...
|
||||||
|
break; // We found it, exit the loop!
|
||||||
|
} // If we didn't, just continue.
|
||||||
}
|
}
|
||||||
}
|
} // And now we have our 'select' value.
|
||||||
|
|
||||||
selected:
|
|
||||||
|
|
||||||
|
// 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 'preview_c_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 (select >= syntax_count) {
|
||||||
* length = 1;
|
* length = 1;
|
||||||
|
|
||||||
return (syntax_count);
|
return (syntax_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (offset = 1; string [offset - 1] != '\0'; ++offset) {
|
// In this second part, we have our 'select' value, index of the syntax rule, and we want to know the 'length' value, by trying to match with 'syntax_end' string. We have
|
||||||
if (string [offset] == syntax_escape [select]) {
|
// to again, separate two cases for matching any character or full string, except that we use it to determine its' match-length. Important difference is also that there's
|
||||||
|
// special case where we have escape character matching, and where 'syntax_end' string is empty (but not NULL), so in that case we match only one character. We could have
|
||||||
|
// nested loop there, and second loop would need goto statement to exit it, so we only use one loop.
|
||||||
|
for (offset = 1; string [offset - 1] != '\0'; ++offset) { // Now, offset must be 1, and we loop...
|
||||||
|
if (string [offset] == syntax_escape [select]) { // Here's our escape exception.
|
||||||
++offset;
|
++offset;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syntax_derange [select] == FALSE) {
|
if (syntax_derange [select] == FALSE) { // Choosing what to compare, yet again...
|
||||||
if (string_compare_limit (& string [offset], syntax_end [select], string_length (syntax_end [select])) == TRUE) {
|
if (string_compare_limit (& string [offset], syntax_end [select], string_length (syntax_end [select])) == TRUE) { // Again, we're comparing full string.
|
||||||
* length = offset + string_length (syntax_end [select]);
|
* length = offset + string_length (syntax_end [select]); // We found it, yaay!
|
||||||
return (select);
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
subset = 0;
|
if (string_compare (syntax_end [select], "") == TRUE) { // And here's our empty string exception.
|
||||||
if (string_compare (syntax_end [select], "") == TRUE) {
|
|
||||||
break;
|
break;
|
||||||
} do {
|
}
|
||||||
if (string [offset] == syntax_end [select] [subset]) {
|
if (character_compare_array (string [offset], syntax_end [select]) == TRUE) {
|
||||||
* length = offset;
|
* length = offset;
|
||||||
goto finished;
|
break;
|
||||||
}
|
}
|
||||||
} while (++subset != string_length (syntax_end [select]));
|
} // These two loops look similar, but no!
|
||||||
}
|
} // And now we have our 'length' value.
|
||||||
}
|
|
||||||
|
|
||||||
finished:
|
return (select); // Lastly, return syntax rule index.
|
||||||
|
|
||||||
return (select);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Imagine my shock, we can now print coloured text, without regular expressions. Nothing much, we can print it without using 'curses_*' functions, but if we want to preview large,
|
||||||
|
well more than 24 line of code, we'd want to scroll it or modify it if we're making a text editor, hence, using curses is good. Lets see how our "mini-main" subprogram-like
|
||||||
|
function does its' work, and how we use 'syntax_*' functions in them.
|
||||||
|
*/
|
||||||
|
|
||||||
void preview_c_file (char * text_file, int width, int height, int x, int y) {
|
void preview_c_file (char * text_file, int width, int height, int x, int y) {
|
||||||
|
// Before we begin (Ada pun intended, remove this in final version), I won't (re)align 'separators' and 'keywords', because they fuck-up my comments, which I never write
|
||||||
|
// in my "official" programs. I write comments only here, to explain stuff in more details. Have fun... Oh, and type of variable 'keywords' an array of string pointers of
|
||||||
|
// automatic length, which we get with "sizeof (keywords) / sizeof (keywords [0])" part, for those keywords, it would be 32UL, and we cast it to integer.
|
||||||
char * separators = ".,:;<=>+*-/%!&~^?|()[]{}'\" \t\r\n";
|
char * separators = ".,:;<=>+*-/%!&~^?|()[]{}'\" \t\r\n";
|
||||||
|
|
||||||
char * keywords [] = {
|
char * keywords [] = {
|
||||||
@ -240,7 +248,7 @@ void preview_c_file (char * text_file, int width, int height, int x, int y) {
|
|||||||
(void) width;
|
(void) width;
|
||||||
(void) height;
|
(void) height;
|
||||||
|
|
||||||
syntax_define (FALSE, FALSE, "/*", "*/", '\0', COLOUR_GREY, EFFECT_BOLD);
|
syntax_define (FALSE, FALSE, "/*", "*/", '\0', COLOUR_GREY, EFFECT_BOLD); // Below, we're simply using our 'syntax_define' function.
|
||||||
syntax_define (FALSE, FALSE, "//", "\n", '\0', COLOUR_GREY, EFFECT_BOLD);
|
syntax_define (FALSE, FALSE, "//", "\n", '\0', COLOUR_GREY, EFFECT_BOLD);
|
||||||
syntax_define (FALSE, FALSE, "#", "\n", '\\', COLOUR_YELLOW, EFFECT_ITALIC);
|
syntax_define (FALSE, FALSE, "#", "\n", '\\', COLOUR_YELLOW, EFFECT_ITALIC);
|
||||||
syntax_define (FALSE, FALSE, "'", "'", '\\', COLOUR_PINK, EFFECT_BOLD);
|
syntax_define (FALSE, FALSE, "'", "'", '\\', COLOUR_PINK, EFFECT_BOLD);
|
||||||
@ -258,27 +266,33 @@ void preview_c_file (char * text_file, int width, int height, int x, int y) {
|
|||||||
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
|
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
|
||||||
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
|
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
|
||||||
|
|
||||||
text_data = file_record (text_file);
|
text_data = file_record (text_file); // And, imagine, importing our file data into a buffer!
|
||||||
|
|
||||||
reset_x = x;
|
reset_x = x;
|
||||||
reset_y = y;
|
reset_y = y;
|
||||||
|
|
||||||
for (curses_active = 1; curses_active != 0; ) {
|
for (curses_active = 1; curses_active != 0; ) { // We enter our main subprogram loop.
|
||||||
int offset, select, length;
|
int offset, select, length;
|
||||||
|
|
||||||
curses_render_background (' ', COLOUR_WHITE, EFFECT_NORMAL);
|
curses_render_background (' ', COLOUR_WHITE, EFFECT_NORMAL); // We need to clear the screen buffer before rendering.
|
||||||
|
|
||||||
x = reset_x;
|
x = reset_x;
|
||||||
y = reset_y;
|
y = reset_y;
|
||||||
select = syntax_count;
|
select = syntax_count;
|
||||||
length = 0;
|
length = 0;
|
||||||
|
|
||||||
for (offset = 0; offset < string_length (text_data); offset += length) {
|
for (offset = 0; offset < string_length (text_data); offset += length) { // And it's time to start rendering our C file.
|
||||||
int suboffset, colour, effect;
|
int suboffset, colour, effect;
|
||||||
|
|
||||||
select = syntax_select (& text_data [offset], & length);
|
select = syntax_select (& text_data [offset], & length); // Here we're evaluating variables 'select' and 'length'.
|
||||||
|
|
||||||
if (select >= syntax_count) {
|
// We can do the same thing in 2 lines of code, but it's less readable in my opinion, I prefer longer verbose way below...
|
||||||
|
// colour = (select >= syntax_count) ? COLOUR_WHITE : syntax_colour [select];
|
||||||
|
// effect = (select >= syntax_count) ? EFFECT_NORMAL : syntax_effect [select];
|
||||||
|
// 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;
|
||||||
|
if (select >= syntax_count) { // Here, we're handling error value of 'syntax_select'.
|
||||||
colour = COLOUR_WHITE;
|
colour = COLOUR_WHITE;
|
||||||
effect = EFFECT_NORMAL;
|
effect = EFFECT_NORMAL;
|
||||||
} else {
|
} else {
|
||||||
@ -286,25 +300,23 @@ void preview_c_file (char * text_file, int width, int height, int x, int y) {
|
|||||||
effect = syntax_effect [select];
|
effect = syntax_effect [select];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (suboffset = 0; suboffset < length; ++suboffset) {
|
for (suboffset = 0; suboffset < length; ++suboffset) { // Sadly, we need to render them one by one character.
|
||||||
if (text_data [offset + suboffset] == CHARACTER_LINE_FEED) {
|
if (text_data [offset + suboffset] == CHARACTER_LINE_FEED) { // Rendering of blank characters isn't counted, so:
|
||||||
x = reset_x;
|
x = reset_x; // If there's a new line, we need to reset 'x' value.
|
||||||
y += 1;
|
y += 1; // And increment 'y' value.
|
||||||
} else if (text_data [offset + suboffset] == CHARACTER_TAB_HORIZONTAL) {
|
} else if (text_data [offset + suboffset] == CHARACTER_TAB_HORIZONTAL) { // If there's a tab, we offset 'x' value by normal count.
|
||||||
x += 8;
|
x += 8; // Normal indentation is 8-characters wide.
|
||||||
} else {
|
} else {
|
||||||
curses_render_character (text_data [offset + suboffset], colour, effect, x, y);
|
curses_render_character (text_data [offset + suboffset], colour, effect, x, y); // Finally, we can render it character by character.
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// curses_render_string_limit (& text_data [offset], length, syntax_colour [select], syntax_effect [select], x, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curses_synchronize ();
|
curses_synchronize (); // Lastly, we synchronize our terminal.
|
||||||
}
|
}
|
||||||
|
|
||||||
text_data = deallocate (text_data);
|
text_data = deallocate (text_data); // And deallocate the memory when we exit the subprogram.
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user