forked from xolatile/xhartae
260 lines
18 KiB
C
260 lines
18 KiB
C
/*
|
|
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic
|
|
|
|
Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
|
|
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
|
|
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 CHAPTER_1_SOURCE
|
|
#define CHAPTER_1_SOURCE
|
|
|
|
#include "chapter_1.h"
|
|
|
|
/*
|
|
In functions 'character_is_uppercase', 'character_is_lowercase' and 'character_is_digit', we use characters that are in certain range on ASCII table, which we'll show just below.
|
|
So, it's safe to use '>=' and '<=' operators, but in other cases, we want to compare them selectively, and for simplicity we use function 'character_compare_array'... Here's how
|
|
ASCII table looks like, I don't like encodings like UTF-8 and others, so neither should you. We'll also write a subprogram that prints this to terminal or graphical window.
|
|
|
|
ASCII table:
|
|
_______________________________________________________________________________________________________________________________________________________________
|
|
| 0B | 0O | 0D | 0X | SYM | Full name | 0B | 0O | 0D | 0X | SYM | Full name |
|
|
|_______________________________________________________________________________|_______________________________________________________________________________|
|
|
| | |
|
|
| 0000000 | 000 | 0 | 00 | NUL | Null | 0000001 | 001 | 1 | 01 | SOH | Start of heading |
|
|
| 0000010 | 002 | 2 | 02 | STX | Start of text | 0000011 | 003 | 3 | 03 | ETX | End of text |
|
|
| 0000100 | 004 | 4 | 04 | EOT | End of transmission | 0000101 | 005 | 5 | 05 | ENQ | Enquiry |
|
|
| 0000110 | 006 | 6 | 06 | ACK | Acknowledge | 0000111 | 007 | 7 | 07 | BEL | Bell |
|
|
| 0001000 | 010 | 8 | 08 | BS | Backspace | 0001001 | 011 | 9 | 09 | HT | Horizontal tab |
|
|
| 0001010 | 012 | 10 | 0A | LF | Line feed | 0001011 | 013 | 11 | 0B | VT | Vertical tab |
|
|
| 0001100 | 014 | 12 | 0C | FF | Form feed | 0001101 | 015 | 13 | 0D | CR | Carriage return |
|
|
| 0001110 | 016 | 14 | 0E | SO | Shift out | 0001111 | 017 | 15 | 0F | SI | Shift in |
|
|
| 0010000 | 020 | 16 | 10 | DLE | Data link escape | 0010001 | 021 | 17 | 11 | DC1 | Device control 1 |
|
|
| 0010010 | 022 | 18 | 12 | DC2 | Device control 2 | 0010011 | 023 | 19 | 13 | DC3 | Device control 3 |
|
|
| 0010100 | 024 | 20 | 14 | DC4 | Device control 4 | 0010101 | 025 | 21 | 15 | NAK | Negative acknowledge |
|
|
| 0010110 | 026 | 22 | 16 | SYN | Synchronous idle | 0010111 | 027 | 23 | 17 | ETB | End transmission block |
|
|
| 0011000 | 030 | 24 | 18 | CAN | Cancel | 0011001 | 031 | 25 | 19 | EM | End of medium |
|
|
| 0011010 | 032 | 26 | 1A | SUB | Substitute | 0011011 | 033 | 27 | 1B | ESC | Escape |
|
|
| 0011100 | 034 | 28 | 1C | FS | File separator | 0011101 | 035 | 29 | 1D | GS | Group separator |
|
|
| 0011110 | 036 | 30 | 1E | RS | Record separator | 0011111 | 037 | 31 | 1F | US | Unit separator |
|
|
| 0100000 | 040 | 32 | 20 | | Space | 0100001 | 041 | 33 | 21 | ! | Exclamation mark |
|
|
| 0100010 | 042 | 34 | 22 | " | Speech mark | 0100011 | 043 | 35 | 23 | # | Number sign |
|
|
| 0100100 | 044 | 36 | 24 | $ | Dollar sign | 0100101 | 045 | 37 | 25 | % | Percent |
|
|
| 0100110 | 046 | 38 | 26 | & | Ampersand | 0100111 | 047 | 39 | 27 | ' | Quote |
|
|
| 0101000 | 050 | 40 | 28 | ( | Open parenthesis | 0101001 | 051 | 41 | 29 | ) | Close parenthesis |
|
|
| 0101010 | 052 | 42 | 2A | * | Asterisk | 0101011 | 053 | 43 | 2B | + | Plus |
|
|
| 0101100 | 054 | 44 | 2C | , | Comma | 0101101 | 055 | 45 | 2D | - | Minus |
|
|
| 0101110 | 056 | 46 | 2E | . | Period | 0101111 | 057 | 47 | 2F | / | Slash |
|
|
| 0110000 | 060 | 48 | 30 | 0 | Zero | 0110001 | 061 | 49 | 31 | 1 | One |
|
|
| 0110010 | 062 | 50 | 32 | 2 | Two | 0110011 | 063 | 51 | 33 | 3 | Three |
|
|
| 0110100 | 064 | 52 | 34 | 4 | Four | 0110101 | 065 | 53 | 35 | 5 | Five |
|
|
| 0110110 | 066 | 54 | 36 | 6 | Six | 0110111 | 067 | 55 | 37 | 7 | Seven |
|
|
| 0111000 | 070 | 56 | 38 | 8 | Eight | 0111001 | 071 | 57 | 39 | 9 | Nine |
|
|
| 0111010 | 072 | 58 | 3A | : | Colon | 0111011 | 073 | 59 | 3B | ; | Semicolon |
|
|
| 0111100 | 074 | 60 | 3C | < | Open angled bracket | 0111101 | 075 | 61 | 3D | = | Equal |
|
|
| 0111110 | 076 | 62 | 3E | > | Close angled bracket | 0111111 | 077 | 63 | 3F | ? | Question mark |
|
|
| 1000000 | 100 | 64 | 40 | @ | At sign | 1000001 | 101 | 65 | 41 | A | Uppercase A |
|
|
| 1000010 | 102 | 66 | 42 | B | Uppercase B | 1000011 | 103 | 67 | 43 | C | Uppercase C |
|
|
| 1000100 | 104 | 68 | 44 | D | Uppercase D | 1000101 | 105 | 69 | 45 | E | Uppercase E |
|
|
| 1000110 | 106 | 70 | 46 | F | Uppercase F | 1000111 | 107 | 71 | 47 | G | Uppercase G |
|
|
| 1001000 | 110 | 72 | 48 | H | Uppercase H | 1001001 | 111 | 73 | 49 | I | Uppercase I |
|
|
| 1001010 | 112 | 74 | 4A | J | Uppercase J | 1001011 | 113 | 75 | 4B | K | Uppercase K |
|
|
| 1001100 | 114 | 76 | 4C | L | Uppercase L | 1001101 | 115 | 77 | 4D | M | Uppercase M |
|
|
| 1001110 | 116 | 78 | 4E | N | Uppercase N | 1001111 | 117 | 79 | 4F | O | Uppercase O |
|
|
| 1010000 | 120 | 80 | 50 | P | Uppercase P | 1010001 | 121 | 81 | 51 | Q | Uppercase Q |
|
|
| 1010010 | 122 | 82 | 52 | R | Uppercase R | 1010011 | 123 | 83 | 53 | S | Uppercase S |
|
|
| 1010100 | 124 | 84 | 54 | T | Uppercase T | 1010101 | 125 | 85 | 55 | U | Uppercase U |
|
|
| 1010110 | 126 | 86 | 56 | V | Uppercase V | 1010111 | 127 | 87 | 57 | W | Uppercase W |
|
|
| 1011000 | 130 | 88 | 58 | X | Uppercase X | 1011001 | 131 | 89 | 59 | Y | Uppercase Y |
|
|
| 1011010 | 132 | 90 | 5A | Z | Uppercase Z | 1011011 | 133 | 91 | 5B | [ | Opening bracket |
|
|
| 1011100 | 134 | 92 | 5C | \ | Backslash | 1011101 | 135 | 93 | 5D | ] | Closing bracket |
|
|
| 1011110 | 136 | 94 | 5E | ^ | Caret | 1011111 | 137 | 95 | 5F | _ | Underscore |
|
|
| 1100000 | 140 | 96 | 60 | ` | Grave | 1100001 | 141 | 97 | 61 | a | Lowercase a |
|
|
| 1100010 | 142 | 98 | 62 | b | Lowercase b | 1100011 | 143 | 99 | 63 | c | Lowercase c |
|
|
| 1100100 | 144 | 100 | 64 | d | Lowercase d | 1100101 | 145 | 101 | 65 | e | Lowercase e |
|
|
| 1100110 | 146 | 102 | 66 | f | Lowercase f | 1100111 | 147 | 103 | 67 | g | Lowercase g |
|
|
| 1101000 | 150 | 104 | 68 | h | Lowercase h | 1101001 | 151 | 105 | 69 | i | Lowercase i |
|
|
| 1101010 | 152 | 106 | 6A | j | Lowercase j | 1101011 | 153 | 107 | 6B | k | Lowercase k |
|
|
| 1101100 | 154 | 108 | 6C | l | Lowercase l | 1101101 | 155 | 109 | 6D | m | Lowercase m |
|
|
| 1101110 | 156 | 110 | 6E | n | Lowercase n | 1101111 | 157 | 111 | 6F | o | Lowercase o |
|
|
| 1110000 | 160 | 112 | 70 | p | Lowercase p | 1110001 | 161 | 113 | 71 | q | Lowercase q |
|
|
| 1110010 | 162 | 114 | 72 | r | Lowercase r | 1110011 | 163 | 115 | 73 | s | Lowercase s |
|
|
| 1110100 | 164 | 116 | 74 | t | Lowercase t | 1110101 | 165 | 117 | 75 | u | Lowercase u |
|
|
| 1110110 | 166 | 118 | 76 | v | Lowercase v | 1110111 | 167 | 119 | 77 | w | Lowercase w |
|
|
| 1111000 | 170 | 120 | 78 | x | Lowercase x | 1111001 | 171 | 121 | 79 | y | Lowercase y |
|
|
| 1111010 | 172 | 122 | 7A | z | Lowercase z | 1111011 | 173 | 123 | 7B | { | Opening brace |
|
|
| 1111100 | 174 | 124 | 7C | | | Vertical bar | 1111101 | 175 | 125 | 7D | } | Closing brace |
|
|
| 1111110 | 176 | 126 | 7E | ~ | Tilde | 1111111 | 177 | 127 | 7F | DEL | Delete |
|
|
|_______________________________________________________________________________|_______________________________________________________________________________|
|
|
|
|
You can see that values of 'A' ... 'Z', 'a' ... 'z' and '0' ... '9' are sequential, but symbols and "system" characters are mixed up.
|
|
*/
|
|
|
|
int character_is_uppercase (char character) {
|
|
return ((int) ((character >= 'A') && (character <= 'Z')));
|
|
}
|
|
|
|
int character_is_lowercase (char character) {
|
|
return ((int) ((character >= 'a') && (character <= 'z')));
|
|
}
|
|
|
|
int character_is_digit (char character) {
|
|
return ((int) ((character >= '0') && (character <= '9')));
|
|
}
|
|
|
|
int character_is_blank (char character) { // Standard implementation also considers vertical tab and form feed as blank, we don't...
|
|
return ((int) ((character == ' ') || (character == CHARACTER_TAB_HORIZONTAL) || (character == CHARACTER_CARRIAGE_RETURN) || (character == CHARACTER_LINE_FEED)));
|
|
// If you like smaller line length limit, you can align it like this:
|
|
// return ((character == ' ')
|
|
// || (character == CHARACTER_TAB_HORIZONTAL)
|
|
// || (character == CHARACTER_CARRIAGE_RETURN)
|
|
// || (character == CHARACTER_LINE_FEED));
|
|
// Or:
|
|
// return ((character == ' ') ||
|
|
// (character == CHARACTER_TAB_HORIZONTAL) ||
|
|
// (character == CHARACTER_CARRIAGE_RETURN) ||
|
|
// (character == CHARACTER_LINE_FEED));
|
|
// Or even use literal characters:
|
|
// return ((character == ' ') ||
|
|
// (character == '\t') ||
|
|
// (character == '\r') ||
|
|
// (character == '\n'));
|
|
}
|
|
|
|
int character_is_alpha (char character) { // Returns TRUE / 1 or FALSE / 0 depending on if the character is either uppercase or lowercase.
|
|
return ((character_is_uppercase (character) != 0) || (character_is_lowercase (character) != 0));
|
|
}
|
|
|
|
int character_is_symbol (char character) { // Returns TRUE / 1 if character is one of the characters in that string (array of characters), otherwise it returns FALSE / 0.
|
|
return (character_compare_array (character, "~!@#$%^&*()+{}|:\"<>?`-=[]\\;',./"));
|
|
}
|
|
|
|
int character_is_visible (char character) { // This is visible (printable) character range, and space is included in there.
|
|
return ((int) ((character >= ' ') && (character <= '~')));
|
|
}
|
|
|
|
int character_is_invisible (char character) { // If character is not visible, then guess what? It's invisible.
|
|
return (character_is_visible (character) == FALSE);
|
|
}
|
|
|
|
int character_is_escape (char character) { // We might use this function...
|
|
return ((int) (character == CHARACTER_ESCAPE));
|
|
}
|
|
|
|
int character_is_underscore (char character) { // I don't even know if I'll ever use this one, we'll see, I'm in the process of writing this "book"...
|
|
return ((int) (character == '_'));
|
|
}
|
|
|
|
int character_is_hexadecimal (char character) { // Same as function 'character_is_symbol', but for hexadecimal digits.
|
|
return (character_compare_array (character, "0123456789ABCDEF"));
|
|
}
|
|
|
|
int character_compare_array (char character, char * character_array) { // I didn't use name "string", but "character_array", to explicitly show the intention of argument.
|
|
int offset;
|
|
|
|
for (offset = 0; offset != string_length (character_array); ++offset) { // We iterate through string (character array!) and return TRUE / 1 if we found it.
|
|
if (character == character_array [offset]) { // If we don't find it in that string, we return FALSE / 0 since it's not there.
|
|
return (TRUE); // Note that we could do this without the variable 'offset', similar to string functions.
|
|
}
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
int file_open (char * name, int mode) {
|
|
int descriptor = -1;
|
|
|
|
fatal_failure (name == NULL, "file_open: Failed to open file, name is null pointer.");
|
|
|
|
descriptor = open (name, mode);
|
|
|
|
fatal_failure (descriptor == -1, "file_open: Failed to open file, function open returned invalid descriptor.");
|
|
|
|
return (descriptor);
|
|
}
|
|
|
|
int file_close (int file) {
|
|
fatal_failure (file == -1, "file_close: Failed to close file, invalid file descriptor.");
|
|
fatal_failure (close (file) == -1, "file_close: Failed to close file, function close returned invalid code.");
|
|
|
|
return (-1);
|
|
}
|
|
|
|
void file_read (int file, void * data, int size) {
|
|
fatal_failure (file == -1, "file_read: Failed to read from file, invalid descriptor.");
|
|
fatal_failure (data == NULL, "file_read: Failed to read from file, data is null pointer.");
|
|
fatal_failure (size == 0, "file_read: Failed to read from file, size is zero.");
|
|
|
|
(void) read (file, data, (unsigned long int) size);
|
|
}
|
|
|
|
void file_write (int file, void * data, int size) {
|
|
fatal_failure (file == -1, "file_write: Failed to write to file, invalid descriptor.");
|
|
fatal_failure (data == NULL, "file_write: Failed to write to file, data is null pointer.");
|
|
fatal_failure (size == 0, "file_write: Failed to write to file, size is zero.");
|
|
|
|
(void) write (file, data, (unsigned long int) size);
|
|
}
|
|
|
|
int file_seek (int file, int whence) {
|
|
fatal_failure (file == -1, "file_seek: Failed to seek in file, invalid descriptor.");
|
|
|
|
return ((int) lseek (file, 0, whence));
|
|
}
|
|
|
|
int file_size (char * name) {
|
|
int size = -1;
|
|
int file = -1;
|
|
|
|
file = file_open (name, O_RDONLY);
|
|
|
|
size = lseek (file, 0, SEEK_END);
|
|
|
|
fatal_failure (size == -1, "file_size: Failed to get size of file, invalid file size.");
|
|
|
|
file = file_close (file);
|
|
|
|
return (size);
|
|
}
|
|
|
|
int file_type (char * name) {
|
|
char * file_type_data [FILE_TYPE_COUNT] = {
|
|
".txt", ".s", ".fasm", ".gasm", ".nasm", ".yasm", ".c", ".h",
|
|
".adb", ".ads", ".cpp", ".hpp"
|
|
};
|
|
|
|
int type = 0;
|
|
|
|
while (* name != '.') {
|
|
++name;
|
|
}
|
|
|
|
for (type = 0; type != FILE_TYPE_COUNT; ++type) {
|
|
if (string_compare (name, file_type_data [type]) != 0) {
|
|
return (type);
|
|
}
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
void * file_record (char * name) {
|
|
int file = -1;
|
|
int size = -1;
|
|
char * data = NULL;
|
|
|
|
fatal_failure (name == NULL, "file_import: Failed to import file, name is null pointer.");
|
|
|
|
file = file_open (name, O_RDONLY);
|
|
size = file_size (name);
|
|
data = allocate (size);
|
|
|
|
file_read (file, data, size);
|
|
|
|
file = file_close (file);
|
|
|
|
return (data);
|
|
}
|
|
|
|
#endif
|