From 9fe317897415916c86102a916a2ac85987106a3b Mon Sep 17 00:00:00 2001 From: Ognjen Milan Robovic Date: Fri, 18 Apr 2025 15:16:15 +0000 Subject: Whatever... Please Emil for the love of Gott... --- xcript.h | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 xcript.h (limited to 'xcript.h') 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); +} -- cgit v1.2.3