aboutsummaryrefslogtreecommitdiff
path: root/xcript.h
diff options
context:
space:
mode:
authorOgnjen Milan Robovic2025-04-18 15:16:15 +0000
committerOgnjen Milan Robovic2025-04-18 15:16:15 +0000
commit9fe317897415916c86102a916a2ac85987106a3b (patch)
treeb712d4945a94c73e6ca7c2f34a3451067948c160 /xcript.h
parentc13ebf13e5df4b04285c6c330a25ebce10071555 (diff)
downloadxolatile-xolatilization-9fe317897415916c86102a916a2ac85987106a3b.tar.xz
xolatile-xolatilization-9fe317897415916c86102a916a2ac85987106a3b.tar.zst
Whatever...HEADmaster
Please Emil for the love of Gott...
Diffstat (limited to 'xcript.h')
-rw-r--r--xcript.h383
1 files changed, 383 insertions, 0 deletions
diff --git a/xcript.h b/xcript.h
new file mode 100644
index 0000000..cf5183f
--- /dev/null
+++ b/xcript.h
@@ -0,0 +1,383 @@
+/// _ _
+/// __ _____ _ __(_)_ __ | |_
+/// \ \/ / __| '__| | '_ \| __|
+/// > < (__| | | | |_) | |_
+/// /_/\_\___|_| |_| .__/ \__|
+/// |_|
+///
+/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
+///
+/// xolatile@chud.cyou - xcript - Whitespace insignificant INI/CFG-like script parser.
+///
+/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU
+/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish...
+///
+/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
+/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
+/// for more details, if you dare, it is a lot of text that nobody wants to read...
+
+typedef enum {
+ script_unknown, script_comment, script_string, script_number, script_marker, script_header, script_assign, script_end,
+ script_from, script_to, script_next
+} script_word_type;
+
+typedef struct {
+ character * path;
+ character * source;
+ natural prefix;
+ natural length;
+ natural suffix;
+ natural offset;
+ natural line;
+ natural last_length;
+ character * last_string;
+ boolean force;
+ boolean range;
+} script_data_structure;
+
+typedef struct {
+ natural counter;
+ character * * identifier;
+ natural * index;
+} script_structure;
+
+static procedure script_warning (script_data_structure * script, boolean condition, character * message) {
+ if (condition == true) {
+ print ("/w %s: %i: %s\n", script->path, script->line, message);
+ }
+}
+
+static procedure script_failure (script_data_structure * script, boolean condition, character * message) {
+ if (condition == true) {
+ print ("/f %s: %i: %s\n", script->path, script->line, message);
+
+ print ("/1%s/-", & script->source [script->offset]);
+
+ exit (log_failure);
+ }
+}
+
+static script_data_structure * script_open (character * path) {
+ script_data_structure * script = allocate (sizeof (* script));
+
+ script->path = string_duplicate (path);
+ script->source = file_import (path);
+
+ script->prefix = 0;
+ script->length = 0;
+ script->suffix = 0;
+ script->offset = 0;
+ script->line = 1;
+ script->last_length = 0;
+ script->last_string = & script->source [0];
+
+ return (script);
+}
+
+static script_data_structure * script_close (script_data_structure * script) {
+ script->path = deallocate (script->path);
+ script->source = deallocate (script->source);
+
+ return (deallocate (script));
+}
+
+static boolean script_compare (script_data_structure * script, character * string) {
+ return (string_compare_limit (string, script->last_string, script->last_length));
+}
+
+static boolean script_check (script_structure * information, natural index, character * identifier) {
+ return (string_compare (identifier, information->identifier [index]));
+}
+
+static character * script_export_string (script_data_structure * script) {
+ return (string_duplicate_limit (script->last_string, script->last_length));
+}
+
+static natural script_export_number (script_data_structure * script) {
+ return (string_limit_to_number (script->last_string, script->last_length));
+}
+
+static natural script_export_marker (script_structure * information, script_data_structure * script) {
+ for (natural counter = 0; counter < information->counter; ++counter) {
+ if (script_compare (script, information->identifier [counter]) == true) {
+ return (information->index [counter]);
+ }
+ }
+
+ script_failure (script, true, "No such identifier defined so far in any of the headers!");
+
+ return (~ 0u);
+}
+
+static script_word_type script_parser (script_data_structure * script) {
+ script_word_type word = script_unknown;
+
+ script->prefix = 0;
+ script->length = 0;
+ script->suffix = 0;
+
+ for (; character_is_blank (script->source [script->offset + script->prefix]) == true; ++script->prefix) {
+ if (script->source [script->offset + script->prefix] == '\n') {
+ ++script->line;
+ }
+ }
+
+ if (script->source [script->offset + script->prefix] == '\0') {
+ word = script_end;
+ } else if (script->source [script->offset + script->prefix] == '(') {
+ script_failure (script, script->range == true, "You are already defining a range, only one pair of () is allowed.");
+ script->range = true;
+ ++script->length;
+ word = script_from;
+ } else if (script->source [script->offset + script->prefix] == ',') {
+ script_failure (script, script->range == false, "You can't use ',' outside of a range.");
+ ++script->length;
+ word = script_next;
+ } else if (script->source [script->offset + script->prefix] == ')') {
+ script_failure (script, script->range == false, "You already defined a range, only one pair of () is allowed.");
+ script->range = false;
+ ++script->length;
+ word = script_to;
+ } else if (script->source [script->offset + script->prefix] == ';') {
+ for (; script->source [script->offset + script->prefix + script->length] != '\n'; ++script->length) {
+ script_warning (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Expected at least a trailing new line or some blank character after a comment!");
+ }
+ word = script_comment;
+ } else if (script->source [script->offset + script->prefix] == '#') {
+ for (; script->source [script->offset + script->prefix + script->length] != '\n'; ++script->length) {
+ script_warning (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Expected at least a trailing new line or some blank character after a comment!");
+ }
+ word = script_comment;
+ } else if (script->source [script->offset + script->prefix] == '=') {
+ ++script->length;
+ word = script_assign;
+ } else if (script->source [script->offset + script->prefix] == '"') {
+ script_failure (script, script->range == true, "You can't use string inside of a range.");
+ for (script->length = 1; script->source [script->offset + script->prefix + script->length] != '"'; ++script->length) {
+ script_failure (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Unterminated string literal, missing '\"' character.");
+ }
+ ++script->prefix;
+ --script->length;
+ ++script->suffix;
+ word = script_string;
+ } else if (script->source [script->offset + script->prefix] == '\'') {
+ script_failure (script, script->range == true, "You can't use string inside of a range.");
+ for (script->length = 1; script->source [script->offset + script->prefix + script->length] != '\''; ++script->length) {
+ script_failure (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Unterminated string literal, missing ''' character.");
+ }
+ ++script->prefix;
+ --script->length;
+ ++script->suffix;
+ word = script_string;
+ } else if (script->source [script->offset + script->prefix] == '[') {
+ script_failure (script, script->range == true, "You can't use header inside of a range.");
+ for (; script->source [script->offset + script->prefix + script->length] != ']'; ++script->length) {
+ script_failure (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Unterminated header element, missing ']' character.");
+ }
+ ++script->prefix;
+ --script->length;
+ ++script->suffix;
+ word = script_header;
+ } else if (character_is_digit (script->source [script->offset + script->prefix]) == true) {
+ for (; character_is_digit (script->source [script->offset + script->prefix + script->length]) == true; ++script->length) {
+ script_warning (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Expected at least a trailing new line or some blank character after a number!");
+ }
+ word = script_number;
+ } else if (character_is_identifier (script->source [script->offset + script->prefix]) == true) {
+ for (; character_is_identifier (script->source [script->offset + script->prefix + script->length]) == true; ++script->length) {
+ script_warning (script, script->source [script->offset + script->prefix + script->length] == '\0',
+ "Expected at least a trailing new line or some blank character after a marker!");
+ }
+ word = script_marker;
+ } else {
+ script_failure (script, true, format ("Illegal character '%c' in script.", script->source [script->offset + script->prefix]));
+ }
+
+ script->last_string = & script->source [script->offset + script->prefix];
+ script->last_length = script->length;
+
+ script->offset += script->prefix + script->length + script->suffix;
+
+ return (word);
+}
+
+static character * script_expect_header (script_structure * information, script_data_structure * script, natural index, boolean accept) {
+ if (accept == true) {
+ ++information->counter;
+
+ information->identifier = reallocate (information->identifier, information->counter * sizeof (* information->identifier));
+ information->index = reallocate (information->index, information->counter * sizeof (* information->index));
+
+ information->identifier [information->counter - 1] = string_duplicate_limit (script->last_string, script->last_length);
+ information->index [information->counter - 1] = index;
+ }
+
+ return (script_export_string (script));
+}
+
+static character * script_expect_string (script_data_structure * script) {
+ script_word_type word = script_unknown;
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+ script_failure (script, (word = script_parser (script)) != script_string, "Expected string literal.");
+
+ return (script_export_string (script));
+}
+
+static natural script_expect_number (script_data_structure * script) {
+ script_word_type word = script_unknown;
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+ script_failure (script, (word = script_parser (script)) != script_number, "Expected number literal.");
+
+ return (script_export_number (script));
+}
+
+static natural script_expect_marker (script_structure * information, script_data_structure * script) {
+ script_word_type word = script_unknown;
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+ script_failure (script, (word = script_parser (script)) != script_marker, "Expected marker literal.");
+
+ return (script_export_marker (information, script));
+}
+
+static natural script_expect_number_or_marker (script_structure * information, script_data_structure * script) {
+ script_word_type word = script_unknown;
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+
+ word = script_parser (script);
+
+ if (word == script_number) {
+ return (script_export_number (script));
+ } else if (word == script_marker) {
+ return (script_export_marker (information, script));
+ } else {
+ script_failure (script, true, "Expected number or marker literal.");
+ }
+
+ return (~ 0u);
+}
+
+static natural * script_expect_ordered_array (script_structure * information, script_data_structure * script, natural * count) {
+ script_word_type word = script_unknown;
+
+ natural found = 0;
+ natural * array = null;
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+ script_failure (script, (word = script_parser (script)) != script_from, "Expected '(', begin range operator.");
+
+ for (word = script_parser (script); word != script_to; word = script_parser (script)) {
+ ++found;
+
+ array = reallocate (array, found * sizeof (* array));
+
+ if (word == script_number) {
+ array [found - 1] = script_export_number (script);
+ } else if (word == script_marker) {
+ array [found - 1] = script_export_marker (information, script);
+ } else {
+ script_failure (script, true, "Expected number or marker!");
+ }
+
+ if ((word = script_parser (script)) == script_to) break;
+
+ script_failure (script, word != script_next, "Expected ranged next ','.");
+ script_failure (script, word == script_end, "Expected ranged to ')'.");
+ }
+
+ (* count) = found;
+
+ return (array);
+}
+
+static natural * script_expect_unordered_array (script_structure * information, script_data_structure * script, natural count) {
+ script_word_type word = script_unknown;
+
+ natural * array = allocate (count * sizeof (* array));
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+ script_failure (script, (word = script_parser (script)) != script_from, "Expected '(', begin range operator.");
+
+ for (word = script_parser (script); word != script_to; word = script_parser (script)) {
+ natural index = script_export_marker (information, script);
+
+ script_failure (script, word != script_marker, "Expected ranged marker.");
+
+ script_failure (script, (word = script_parser (script)) != script_assign, "Expected '=', assignment operator.");
+
+ word = script_parser (script);
+
+ if (word == script_number) {
+ array [index] = script_export_number (script);
+ } else if (word == script_marker) {
+ array [index] = script_export_marker (information, script);
+ } else {
+ script_failure (script, true, "Expected number or marker!");
+ }
+
+ if ((word = script_parser (script)) == script_to) break;
+
+ script_failure (script, word != script_next, "Expected ranged next ','.");
+ script_failure (script, word == script_end, "Expected ranged to ')'.");
+ }
+
+ return (array);
+}
+
+static script_structure * script_initialize (character * general_script_file_path) {
+ script_structure * script = allocate (sizeof (* script));
+
+ script_word_type word = script_unknown;
+
+ script_data_structure * general = script_open (general_script_file_path);
+
+ for (word = script_parser (general); word != script_end; word = script_parser (general)) {
+ if (word == script_header) {
+ ++script->counter;
+ script->identifier = reallocate (script->identifier, script->counter * sizeof (* script->identifier));
+ script->index = reallocate (script->index, script->counter * sizeof (* script->index));
+ script->identifier [script->counter - 1] = string_duplicate_limit (general->last_string, general->last_length);
+ script->index [script->counter - 1] = script->counter - 1;
+ } else if ((word == script_end) || (word == script_comment)) {
+ continue;
+ } else {
+ script_failure (general, true, "Expected header in general script.");
+ }
+ }
+
+ general = script_close (general);
+
+ return (script);
+}
+
+static script_structure * script_deinitialize (script_structure * script) {
+ for (natural index = 0; index < script->counter; ++index) {
+ script->identifier [index] = deallocate (script->identifier [index]);
+ }
+
+ script->identifier = deallocate (script->identifier);
+ script->index = deallocate (script->index);
+
+ return (deallocate (script));
+}
+
+static natural script_indexer (script_structure * information, character * identifier) {
+ for (natural counter = 0; counter < information->counter; ++counter) {
+ if (string_compare (identifier, information->identifier [counter]) == true) {
+ return (information->index [counter]);
+ }
+ }
+
+ fatal_failure (true, "script_indexer: No such identifier defined so far in any of the headers!");
+
+ return (~ 0u);
+}