From 76f745bd6f59ebd0911b01eb3aabfa730bfe2572 Mon Sep 17 00:00:00 2001 From: Property404 Date: Sun, 20 Aug 2017 14:25:56 -0400 Subject: [PATCH] New fetish: obedience --- docs/c_reference/core.md | 3 + docs/c_reference/obedience.md | 35 ++ docs/reference.md | 4 + docs/reference/core.md | 16 - docs/reference/obedience.md | 27 ++ fetishes/core/fetish.json | 27 -- fetishes/core/source/chain.c | 91 ----- fetishes/core/tests/chain.cpp | 30 -- fetishes/core/unit.fet | 19 - fetishes/obedience/fetish.json | 174 +-------- fetishes/obedience/include/chain.h | 179 --------- fetishes/obedience/include/fileio.h | 37 ++ fetishes/obedience/source/chain.c | 570 ---------------------------- fetishes/obedience/source/fileio.c | 99 +++++ fetishes/obedience/tests/fileio.cpp | 41 ++ fetishes/obedience/unit.fet | 106 +----- scripts/fetlang_reference_make.py | 4 +- src/meson.build | 5 +- 18 files changed, 257 insertions(+), 1210 deletions(-) create mode 100644 docs/c_reference/obedience.md create mode 100644 docs/reference/obedience.md delete mode 100644 fetishes/obedience/include/chain.h create mode 100644 fetishes/obedience/include/fileio.h delete mode 100644 fetishes/obedience/source/chain.c create mode 100644 fetishes/obedience/source/fileio.c create mode 100644 fetishes/obedience/tests/fileio.cpp diff --git a/docs/c_reference/core.md b/docs/c_reference/core.md index d01e0a9..c4ff741 100644 --- a/docs/c_reference/core.md +++ b/docs/c_reference/core.md @@ -17,6 +17,7 @@ `public void `[`read_file_to_chain`](#chain_8h_1a008ca35b36cfa01cebd59a6dddd79671)`(`[`Chain`](#struct_chain)` * chain,`[`Chain`](#struct_chain)` filename)` | Set chain contents to file's contents `public int `[`compare_chains`](#chain_8h_1aebea70af9ccbc3d25da67b8f836dba3d)`(`[`Chain`](#struct_chain)` a,`[`Chain`](#struct_chain)` b)` | Compare chains `public `[`Fraction`](#struct_fraction)` `[`chain_to_fraction`](#chain_8h_1ae351d3cf295fd95456e64cb1bb9216da)`(`[`Chain`](#struct_chain)` chain)` | Convert chain to fraction +`public FILE * `[`open_file_as_stream`](#chain_8h_1a4bea31562c5e8ea9a9dbaece1203119f)`(`[`Chain`](#struct_chain)` filename,const char * mode)` | `public void `[`runtime_error`](#error_8h_1aa4581c050961a458136ec8bdd556d5b5)`(const char * msg,...)` | Show error message and exit `public `[`Fraction`](#struct_fraction)` `[`construct_fraction`](#fraction_8h_1affd36cedc3799420c2d6ddfbdbd81ddf)`(FractionInt num,FractionInt den)` | Construct [Fraction](#struct_fraction) `public `[`Fraction`](#struct_fraction)` `[`random_fraction`](#fraction_8h_1aff0108be8808ee831aaac374030930b4)`()` | Get random fraction @@ -196,6 +197,8 @@ Parse chain to convert to a fraction value. Return 0/1 if chain is invalid. #### Returns The fraction value of the chain +#### `public FILE * `[`open_file_as_stream`](#chain_8h_1a4bea31562c5e8ea9a9dbaece1203119f)`(`[`Chain`](#struct_chain)` filename,const char * mode)` + #### `public void `[`runtime_error`](#error_8h_1aa4581c050961a458136ec8bdd556d5b5)`(const char * msg,...)` Show error message and exit diff --git a/docs/c_reference/obedience.md b/docs/c_reference/obedience.md new file mode 100644 index 0000000..0d5b8e0 --- /dev/null +++ b/docs/c_reference/obedience.md @@ -0,0 +1,35 @@ +# Summary + + Members | Descriptions +--------------------------------|--------------------------------------------- +`public void `[`write_chain_to_file`](#fileio_8h_1a897accbfb97acae9ff091b3dc13921c2)`(Chain chain,Chain filename)` | Set file contents to chain's contents +`public void `[`read_file_to_chain`](#fileio_8h_1a008ca35b36cfa01cebd59a6dddd79671)`(Chain * chain,Chain filename)` | Set chain contents to file's contents +`public FILE * `[`open_file_as_stream`](#fileio_8h_1a4bea31562c5e8ea9a9dbaece1203119f)`(Chain filename,const char * mode)` | + +## Members + +#### `public void `[`write_chain_to_file`](#fileio_8h_1a897accbfb97acae9ff091b3dc13921c2)`(Chain chain,Chain filename)` + +Set file contents to chain's contents + +Open a file and set its contents to that of the chain's. As with other functions, each fraction is converted to a char. An error will be thrown upon any problem opening the file + +#### Parameters +* `chain` The chain being read + +* `filename` A chain holding the filename of the file we're opening + +#### `public void `[`read_file_to_chain`](#fileio_8h_1a008ca35b36cfa01cebd59a6dddd79671)`(Chain * chain,Chain filename)` + +Set chain contents to file's contents + +Open a file and read its contents to the chain's, replacing any previous values(an assign, not append). As with other functions, each char is converted to a fraction. An error will be thrown upon any problem opening the file + +#### Parameters +* `chain` The chain being overwritten + +* `filename` A chain holding the filename of the file we're opening + +#### `public FILE * `[`open_file_as_stream`](#fileio_8h_1a4bea31562c5e8ea9a9dbaece1203119f)`(Chain filename,const char * mode)` + +Generated by [Moxygen](https://sourcey.com/moxygen) \ No newline at end of file diff --git a/docs/reference.md b/docs/reference.md index 2e0bfac..53482fd 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -7,3 +7,7 @@ Core - The included-by-default fetish that defines the language [C Reference](c_reference/core.md) [Fetlang Reference](reference/core.md) +Obedience - File interaction +[C Reference](c_reference/obedience.md) +[Fetlang Reference](reference/obedience.md) + diff --git a/docs/reference/core.md b/docs/reference/core.md index c76707d..2cb1d80 100644 --- a/docs/reference/core.md +++ b/docs/reference/core.md @@ -113,22 +113,6 @@ C Code: /* chain/fraction overload */ append_flink_to_chain(&LHO, RHO) -### fist -Read a file to a chain, given a filename - -C Code: - - /* chain/chain overload */ - read_file_to_chain(&LHO, RHO); - -### obey -Write a chain to file, given a filename - -C Code: - - /* chain/chain overload */ - write_chain_to_file(LHO, RHO) - ## Comparison Operators ### is Return true if LHO==RHO, else return false diff --git a/docs/reference/obedience.md b/docs/reference/obedience.md new file mode 100644 index 0000000..630ac2f --- /dev/null +++ b/docs/reference/obedience.md @@ -0,0 +1,27 @@ +# Obedience +File handling +## Operators +### demand obedience of +Read a file to a chain, given a filename + +C Code: + + /* chain/chain overload */ + read_file_to_chain(&LHO, RHO); + +### obey +Write a chain to file, given a filename + +C Code: + + /* chain/chain overload */ + write_chain_to_file(LHO, RHO) + +### serve +Set LHO as a stream pointing to a file, given a filename + +C Code: + + /* stream/chain overload */ + LHO = open_file_as_stream(RHO, "r+b") + diff --git a/fetishes/core/fetish.json b/fetishes/core/fetish.json index 9dd0ea9..6373355 100644 --- a/fetishes/core/fetish.json +++ b/fetishes/core/fetish.json @@ -95,33 +95,6 @@ "chain/fraction": "append_flink_to_chain(&LHO, RHO)" } }, - { - "name": "demand obedience of", - "description": "Read a file to a chain, given a filename", - "grammars": ["have"], - "code": - { - "chain/chain": "read_file_to_chain(&LHO, RHO);" - } - }, - { - "name": "obey", - "description": "Write a chain to file, given a filename", - "grammars": ["have"], - "code": - { - "chain/chain": "write_chain_to_file(LHO, RHO)" - } - }, - { - "name": "serve", - "description": "Set LHO as a stream pointing to a file, given a filename", - "grammars": ["make"], - "code": - { - "stream/chain": "LHO = open_file_as_stream(RHO, \"r+b\")" - } - }, { "name": "to", "grammars": ["bind"], diff --git a/fetishes/core/source/chain.c b/fetishes/core/source/chain.c index b29caa3..4286dee 100644 --- a/fetishes/core/source/chain.c +++ b/fetishes/core/source/chain.c @@ -427,74 +427,6 @@ Fraction chain_to_fraction(Chain chain) } -void write_chain_to_file(Chain chain, Chain filename_as_chain) -{ - // Convert chain to char* - const int max_filename_size = filename_as_chain.length; - char * filename = (char*)malloc(sizeof(char*) * (max_filename_size + 1)); - if(filename == NULL) - { - runtime_error("Couldn't allocate memory for filename buffer in write_chain_to_file"); - } - memset(filename, 0x00, max_filename_size); - const int size = chain_to_cstr(filename_as_chain, filename); - if(size > max_filename_size) - { - runtime_error("Size is ridiculous is write_chain_to_file"); - } - - // Open the file for writing - FILE* fp = fopen(filename, "wb"); - if(fp == NULL) - { - runtime_error("Could not open file %s for writing", filename); - } - - // Write - Link * it = chain.start; - while(it != NULL) - { - fputc((char)(it->value.num/it->value.den), fp); - it = it->next; - } - - fclose(fp); -} -void read_file_to_chain(Chain * chain, Chain filename_as_chain) -{ - // Convert chain to char* - const int max_filename_size = filename_as_chain.length; - char * filename = (char*)malloc(sizeof(char*) * (max_filename_size + 1)); - if(filename == NULL) - { - runtime_error("Couldn't allocate memory for filename buffer in read_chain_to_file"); - } - memset(filename, 0x00, max_filename_size); - const int size = chain_to_cstr(filename_as_chain, filename); - if(size > max_filename_size) - { - runtime_error("Size is ridiculous is read_file_to_chain"); - } - - // Open the file for reading - FILE* fp = fopen(filename, "rb"); - if(fp == NULL) - { - runtime_error("Could not open file %s for reading", filename); - } - - // Read - while(1) - { - char c = (char)fgetc(fp); - if(c == EOF) break; - append_flink_to_chain(chain, construct_fraction(c, 1)); - } - - fclose(fp); - return; -} - int compare_chains(Chain a, Chain b) { Link *a_iterator = a.start; @@ -545,26 +477,3 @@ void print_chain_numerically(Chain chain) } */ -FILE* open_file_as_stream(Chain filename, const char* mode) -{ - int max_size = sizeof(char)*(filename.length+1); - char* buffer = (char*)malloc(max_size); - if(filename.length == 0 || buffer == NULL) - { - runtime_error("Could not allocate buffer for file"); - } - - int actual_size = chain_to_cstr(filename, buffer); - if(actual_size > filename.length || actual_size <= 0) - { - runtime_error("Something's terribly wrong in open_file_as_stream"); - } - - FILE* fp = fopen(buffer, mode); - if(fp == NULL){ - perror("perror result: "); - runtime_error("Could not open file %s", buffer); - } - return fp; -} - diff --git a/fetishes/core/tests/chain.cpp b/fetishes/core/tests/chain.cpp index cfced1f..c95ce47 100644 --- a/fetishes/core/tests/chain.cpp +++ b/fetishes/core/tests/chain.cpp @@ -23,36 +23,6 @@ TEST_CASE("Chain Test", "[chain]"){ delete[] buffer; } - SECTION("FILE IO") - { - std::string filename = "/tmp/boop2.txt"; - FileUtil::setFileContents(filename, sample_text4); - REQUIRE(FileUtil::getFileContents(filename) == sample_text4); - - Chain filename_as_chain; - init_chain(&filename_as_chain); - append_cstr_to_chain(&filename_as_chain, filename.c_str()); - - Chain chain; - init_chain(&chain); - REQUIRE(chain.length == 0); - - FILE* stream = open_file_as_stream(filename_as_chain, "r+b"); - append_stream_to_chain(&chain, stream); - REQUIRE(chain.length == strlen(sample_text4)); - clear_chain(&chain); - append_cstr_to_chain(&chain, sample_text); - append_chain_to_stream(chain, stream); - clear_chain(&chain); - append_stream_to_chain(&chain, stream); - REQUIRE(chain.length== strlen(sample_text)+strlen(sample_text4)); - - fclose(stream); - clear_chain(&chain); - clear_chain(&filename_as_chain); - - } - SECTION("Chain/stream test"){ std::string filename = "/tmp/bla.txt"; FILE* stream = NULL; diff --git a/fetishes/core/unit.fet b/fetishes/core/unit.fet index 08bbf62..353ee85 100644 --- a/fetishes/core/unit.fet +++ b/fetishes/core/unit.fet @@ -89,25 +89,6 @@ bind reference to chain have reference assert equality with 2 lick count -(file handling) -make hello moan "That's *burp* right\nthey blew up\n" -make filename moan "test.text" -have filename obey hello -have filename demand obedience of contents -have contents assert equality with hello - -(Stream file handling) -make fp serve "test.text" -make slave scream fp -have fp assert equality with hello -make goodbye moan "I'm gonna tell mama" -make fp moan goodbye -have fp assert equality with goodbye -have hello tie up goodbye -have hello tie up fp -have fp assert equality with goodbye - - (Some comparison) make flappy moan diff --git a/fetishes/obedience/fetish.json b/fetishes/obedience/fetish.json index 9dd0ea9..41f2f28 100644 --- a/fetishes/obedience/fetish.json +++ b/fetishes/obedience/fetish.json @@ -1,100 +1,8 @@ { - "name": "core", - "description": "This is the core fetish. It effectively defines the language. You do not need to manually include it.", + "name": "obedience", + "description": "File handling", "operators": [ - { - "name": "spank", - "description": "Subtract the RHO from the LHO", - "grammars": ["have", "plain"], - "examples": ["Spank Linus nine times", "Have Richard spank Linus"], - "code": - { - "fraction/fraction": "LHO=subtract_fractions(LHO, RHO)" - } - }, - { - "name": "worship", - "description": "Multiply the LHO with the RHO", - "grammars": ["have", "plain"], - "examples": ["Worship Amanda's feet", "Have Amanda worship Bruce's throbbing cock"], - "code": - { - "fraction/fraction": "LHO=multiply_fractions(LHO, RHO)" - } - }, - { - "name": "flog", - "description": "Divide the LHO by the RHO", - "grammars": ["have", "plain"], - "examples": ["Flog Amanda", "Have Amanda flog Bruce"], - "code": - { - "fraction/fraction": "LHO=divide_fractions(LHO, RHO)" - } - }, - { - "name": "lick", - "description": "Add the RHO from the LHO", - "grammars": ["have", "plain"], - "examples": ["Lick Linus's face nine times", "Have Richard lick Linus's tummy"], - "code": - { - "fraction/fraction": "LHO=add_fractions(LHO, RHO)" - } - }, - { - "name": "tickle", - "description": "Set the LHO to the remainder of the LHO divided by the RHO", - "grammars": ["have", "plain"], - "examples": ["ticke Richard", "Have Richard tickle Linus"], - "code": - { - "fraction/fraction": "LHO=modulus_fractions(LHO, RHO)" - } - }, - { - "name": "moan", - "description": "Assign RHO to LHO", - "grammars": ["make"], - "code": - { - "fraction/fraction": "LHO=RHO", - "fraction/chain": "LHO=chain_to_fraction(RHO)", - "chain/fraction": "clear_chain(&LHO);append_fraction_to_chain(&LHO, RHO)", - "chain/chain": "clear_chain(&LHO); append_chain_to_chain(&LHO, RHO)" - } - }, - { - "name": "scream", - "description": "Assign RHO to LHO, with new line", - "grammars": ["make"], - "code": - { - "chain/fraction": "clear_chain(&LHO);append_fraction_to_chain(&LHO, RHO);append_flink_to_chain(&LHO, construct_fraction(10,1));", - "chain/chain": "clear_chain(&LHO);append_chain_to_chain(&LHO, RHO);append_flink_to_chain(&LHO, construct_fraction(10,1));" - } - }, - - { - "name": "tie up", - "description": "Concat RHO to LHO", - "grammars": ["have"], - "code": - { - "chain/fraction": "append_fraction_to_chain(&LHO, RHO)", - "chain/chain": "append_chain_to_chain(&LHO, RHO)" - } - }, - { - "name": "hogtie", - "description": "Concat RHO as fraction to LHO", - "grammars": ["have"], - "code": - { - "chain/fraction": "append_flink_to_chain(&LHO, RHO)" - } - }, { "name": "demand obedience of", "description": "Read a file to a chain, given a filename", @@ -121,84 +29,8 @@ { "stream/chain": "LHO = open_file_as_stream(RHO, \"r+b\")" } - }, - { - "name": "to", - "grammars": ["bind"], - "code": - { - "reference/chain": "--this should never enter the C code--" - } - } - - ], - - "comparison_operators": [ - { - "name": "is", - "description": "Return true if LHO==RHO, else return false", - "code": { - "fraction/fraction": "(compare_fractions(LHO, RHO)==0)", - "chain/chain": "(compare_chains(LHO, RHO)==0)" - } - }, - { - "name": "is not", - "description": "Return true if LHO!=RHO, else return false", - "code": { - "fraction/fraction": "(compare_fractions(LHO, RHO)!=0)", - "chain/chain": "(compare_chains(LHO, RHO)!=0)" - } - }, - - { - "name": "is submissive to", - "description": "Return true if LHORHO, else return false", - "code": { - "fraction/fraction": "(compare_fractions(LHO, RHO)==1)" - } - } - ], - - "builtins":[{ - "name": "slave", - "description": "Standard output", - "gender": "unassigned", - "type": "stream", - "code": "stdout" - }, - { - "name": "mistress", - "description": "Standard input", - "gender": "female", - "type": "stream", - "code": "stdin" - }, - { - "name": "dungeon master", - "description": "Standard error", - "gender": "unassigned", - "type": "stream", - "code": "stderr" - }, - { - "name": "saint andrew", - "description": "Chain version of argv with arguments separated by `zero`, intended to be invoked as `Saint Andrew's Cross`", - "gender": "nonperson", - "type": "chain", - "code": "argv_chain" } + ] - ], - - "preloop_code": "Fraction argc_fraction = construct_fraction(argc, 1);\nChain argv_chain;\ninit_chain(&argv_chain);for(int i=0;i -#ifdef __cplusplus -extern "C"{ -#endif - -/* Chains (strings) are represented as doubly linked lists */ -typedef struct Link { - Fraction value; - struct Link *prev; /* Starts at NULL */ - struct Link *next; /* Ends at NULL */ -} Link; -typedef struct Chain { - ChainLengthInt length; - Link *start; - Link *end; -} Chain; - -/** - * Construct chain - * - * Set defaults for chain: length to 0 and start to NULL - * - * @param chain The chain being constructed - */ -void init_chain(Chain * chain); - -/** - * Clear chain - * - * Free all links in chain and set start to NULL - * - * @param chain The chain being cleared - */ -void clear_chain(Chain * chain); - -/** - * Append a cstring to a chain - * - * Append each character of the cstring as a Link to the chain. - * - * @param chain The chain being modified - * @param text The string being added to the chain - */ -void append_cstr_to_chain(Chain * chain, const char *text); - -/** - * Append fraction as single Link to chain - * - * @param chain The chain being modified - * @param fraction The fraction being added to the chain - */ -void append_flink_to_chain(Chain * chain, Fraction fraction); - -/** - * Append fraction as string to chain - * - * Fraction is first converted into a string format. For example, 25/1 would be - * converted to "twenty five" and then appended to the chain - * - * @param chain The chain being modified - * @param fraction The fraction being added to the chain - */ -void append_fraction_to_chain(Chain * chain, Fraction fraction); - -/** - * Append the contents in one chain to another - * - * @param chain1 The chain being modified - * @param chain2 The chain being appended to chain1 - */ -void append_chain_to_chain(Chain * chain1, Chain chain2); - -/** - * Append the contents of a stream to a chain - * - * Each char is read from the stream and copied to the chain as a fraction/Link. - * - * @param chain The chain being modified - * @param stream The stream whose contents are read - */ -void append_stream_to_chain(Chain * chain, FILE * stream); - -/** - * Erase stream contents - * - * @param stream The stream being cleared - */ -void clear_stream(FILE * stream); - -/** - * Append chain to stream - * - * Print each fraction of chain to the stream to be appended as a char - * - * @param chain The chain being read - * @param stream The stream being appended to - */ -void append_chain_to_stream(Chain chain, FILE * stream); - -/** - * Assign chain to stream - * - * Clear the stream, then call append_chain_to_stream - * - * @param chain The chain being read - * @param stream The stream being copied to - */ -void chain_to_stream(Chain chain, FILE * stream); - -/** - * Convert chain to cstring - * - * Print each fraction of chain to the cstring buffer to be appended as a char - * This function is not safe. If buffer is too small to hold the contents of - * chain, a segfault will occur - * - * @param chain The chain being read - * @param buffer The cstring being appended to - * @return The length of the buffer. - */ -int chain_to_cstr(Chain chain, char * buffer); - -/** - * Set file contents to chain's contents - * - * Open a file and set its contents to that of the chain's. As with other - * functions, each fraction is converted to a char. An error will be thrown - * upon any problem opening the file - * - * @param chain The chain being read - * @param filename A chain holding the filename of the file we're opening - */ -void write_chain_to_file(Chain chain, Chain filename); - -/** - * Set chain contents to file's contents - * - * Open a file and read its contents to the chain's, replacing any previous - * values(an assign, not append). As with other functions, each char is - * converted to a fraction. An error will be thrown upon any problem opening - * the file - * - * @param chain The chain being overwritten - * @param filename A chain holding the filename of the file we're opening - */ -void read_file_to_chain(Chain * chain, Chain filename); - -/** - * Compare chains - * - * Check if chaims are equivalent. Will return 0 if they are, and another value - * if they are not. - * - * @param a The first chain - * @param b The second chain - * @return The comparison value - */ -int compare_chains(Chain a, Chain b); - -/* Parse chain to construct fraction */ -/** - * Convert chain to fraction - * - * Parse chain to convert to a fraction value. Return 0/1 if chain is invalid. - * - * @param chain The chain being parsed - * @return The fraction value of the chain - */ -Fraction chain_to_fraction(Chain chain); - -// Experimental -FILE* open_file_as_stream(Chain filename, const char* mode); -#ifdef __cplusplus -} -#endif -#endif diff --git a/fetishes/obedience/include/fileio.h b/fetishes/obedience/include/fileio.h new file mode 100644 index 0000000..27d9dd3 --- /dev/null +++ b/fetishes/obedience/include/fileio.h @@ -0,0 +1,37 @@ +#ifndef FETLANG_FILEIO_H_ +#define FETLANG_FILEIO_H_ +#include "core/include/chain.h" +#ifdef __cplusplus +extern "C"{ +#endif +/** + * Set file contents to chain's contents + * + * Open a file and set its contents to that of the chain's. As with other + * functions, each fraction is converted to a char. An error will be thrown + * upon any problem opening the file + * + * @param chain The chain being read + * @param filename A chain holding the filename of the file we're opening + */ +void write_chain_to_file(Chain chain, Chain filename); + +/** + * Set chain contents to file's contents + * + * Open a file and read its contents to the chain's, replacing any previous + * values(an assign, not append). As with other functions, each char is + * converted to a fraction. An error will be thrown upon any problem opening + * the file + * + * @param chain The chain being overwritten + * @param filename A chain holding the filename of the file we're opening + */ +void read_file_to_chain(Chain * chain, Chain filename); + +// Experimental +FILE* open_file_as_stream(Chain filename, const char* mode); +#ifdef __cplusplus +} +#endif +#endif diff --git a/fetishes/obedience/source/chain.c b/fetishes/obedience/source/chain.c deleted file mode 100644 index b29caa3..0000000 --- a/fetishes/obedience/source/chain.c +++ /dev/null @@ -1,570 +0,0 @@ -#include "core/include/chain.h" -#include "core/include/error.h" -#include "core/include/fraction_math.h" -#include -#include -#include -#include -#include -#include - -void init_chain(Chain * chain) -{ - chain->length = 0; - chain->start = NULL; - chain->end = NULL; -} - -void clear_chain(Chain * chain) -{ - /* Make pointer to first link */ - Link *temp = chain->start; - - /* If it's null, it's already cleared(hopefully) */ - if (chain->start == NULL) - return; - - /* Free all except the last link */ - while (temp->next != NULL) { - temp = temp->next; - free(temp->prev); - } - - /* Free last link */ - free(temp); - - /* Reset chain */ - chain->length = 0; - chain->start = NULL; - chain->end = NULL; -} - -void append_cstr_to_chain(Chain * chain, const char *text) -{ - unsigned int k; - for (k = 0; text[k] != '\0'; k++) { - append_flink_to_chain(chain, - construct_fraction((FractionInt) - text[k], 1)); - } - -} - -void append_flink_to_chain(Chain * chain, Fraction fraction) -{ - /* Create new link */ - Link *new_link = (Link *) malloc(sizeof(Link)); - new_link->value = fraction; - - /* Insert at end */ - new_link->prev = chain->end; - new_link->next = NULL; - if (chain->start == NULL) { - chain->start = new_link; - } else { - chain->end->next = new_link; - } - chain->end = new_link; - - /* Increment length */ - chain->length++; -} - -void append_chain_to_chain(Chain * chain1, Chain chain2) -{ - Link *it = chain2.start; - if (it == NULL) { - return; - } - if (chain1->start == NULL) { - /* Set up iterator as first node */ - chain1->start = (Link *) malloc(sizeof(Link)); - chain1->start->value = it->value; - chain1->start->prev = NULL; - chain1->start->next = NULL; - chain1->end = chain1->start; - } else { - /* Set up iterator at end */ - chain1->end->next = (Link *) malloc(sizeof(Link)); - chain1->end->next->prev = chain1->end; - chain1->end->next->next = NULL; - chain1->end = chain1->end->next; - chain1->end->value = it->value; - } - while (it->next != NULL) { - /* Forward iterator */ - it = it->next; - /* Add node at end */ - chain1->end->next = (Link *) malloc(sizeof(Link)); - chain1->end->next->prev = chain1->end; - chain1->end->next->next = NULL; - chain1->end = chain1->end->next; - chain1->end->value = it->value; - } - - /* Increment length */ - chain1->length += chain2.length; - -} - -void clear_stream(FILE* stream) -{ - // Don't bother with this standard stream nonsense - if(stream == stdin || stream == stdout || stream == stderr) - { - return; - } - - rewind(stream); - if(ftruncate(fileno(stream), 0)) - { - runtime_error("Failed to truncate stream"); - } -} - -void chain_to_stream(Chain chain, FILE* stream) -{ - clear_stream(stream); - append_chain_to_stream(chain, stream); -} - -void append_chain_to_stream(Chain chain, FILE * stream) -{ - if(stream == stdin) - { - return; - } - /* Iterator */ - Link *it = chain.start; - - /* Print out chain */ - while (it != NULL) { - /* Print character */ - fprintf(stream, "%c", - (char) (it->value.num / it->value.den)); - - /* Forward iterator */ - it = it->next; - } -} - -int chain_to_cstr(Chain chain, char * buffer) -{ - /* Iterator */ - Link *it = chain.start; - int count = 0; - - /* Print out chain */ - while (it != NULL) { - /* Print character */ - buffer[count] = (char)(it->value.num / it->value.den); - - /* Forward iterator */ - it = it->next; - - count++; - } - if(count != chain.length) - { - runtime_error("Chain length does not represent true chain length in chain_to_cstr (you should not see this)"); - } - buffer[chain.length] = 0x00; - return count; -} - - -void append_stream_to_chain(Chain * chain, FILE * stream) -{ - if(stream == stdout || stream == stderr) - { - return; - } - char character = 5; - errno = 0; - - if(stream == NULL){ - runtime_error("Stream given does not exist"); - } - if(stream != stdin) - { - rewind(stream); - } - - /* While not end of file */ - character = (char) fgetc(stream); - while (character != EOF) - { - if(errno) - runtime_error("Stream read error"); - - /* Append to chain */ - append_flink_to_chain(chain, - construct_fraction((FractionInt) - character, 1)); - - /* Get character from stream */ - character = (char) fgetc(stream); - } -} - -static void num_to_cstr(char *str, FractionInt num) -{ - /* List numeric literals */ - const char *zero_to_nineteen[] = { - "zero", "one", "two", "three", "four", "five", "six", - "seven", "eight", "nine", "ten", "eleven", - "twelve", "thirteen", "fourteen", "fifteen", "sixteen", - "seventeen", "eighteen", "nineteen" - }; - const char *twenty_to_ninety[] = - { "twenty", "thirty", "forty", "fifty", "sixty", "seventy", - "eighty", "ninety" - }; - const char *big_numbers[] = - { "thousand", "million", "billion", "quadrillion", - "quintillion", "sextillion" - }; - - /* Check for less-than-zero error */ - if (num < 0) { - runtime_error - ("num is less than zero in num_to_cstr(this shouldn't happen)"); - } else - /* Singles and teens */ - if (num < 20) { - strcpy(str, zero_to_nineteen[num]); - } else - /* Adults */ - if (num % 10 == 0 && num < 100) { - strcpy(str, twenty_to_ninety[num / 10 - 2]); - } else - /* Mature */ - if (num % 1000 == 0) { - strcpy(str, big_numbers[(FractionInt) log10(num) / 3 - 1]); - /* Anything else returns an error */ - } else { - runtime_error - ("num(%ji) not valid for num_to_cstr(this shouldn't happen)", - num); - } -} - -static void append_triple_to_chain(Chain * chain, FractionInt triple) -{ - char temp[50]; - /* Error if triple is too big or too small */ - if (triple > 999 || triple < 0) { - runtime_error("invalid triple (you should not see this)"); - } - - /* 100's place */ - if (triple / 100 != 0) { - num_to_cstr(temp, triple / 100); - append_cstr_to_chain(chain, temp); - append_cstr_to_chain(chain, " hundred"); - triple %= 100; - if (triple != 0) { - append_cstr_to_chain(chain, " and "); - } else { - return; - } - - } - - - /* Tens place */ - if (triple / 10 != 0 && triple > 20) { - num_to_cstr(temp, (triple / 10) * 10); - append_cstr_to_chain(chain, temp); - triple %= 10; - if (triple != 0) { - append_cstr_to_chain(chain, " "); - } else { - return; - } - } - - /* Ones place */ - if (triple) { - num_to_cstr(temp, triple); - append_cstr_to_chain(chain, temp); - } - -} - -static void append_fraction_int_to_chain(Chain * chain, FractionInt num) -{ - FractionInt magnitude = 0; - int started = 0; - char temp[50]; - - /* Find magnitude */ - /* Magnitude overflows when num is 10^18 */ - for (magnitude = 1; (num / magnitude) != 0; magnitude *= 1000); - - /* Write to chain */ - while (magnitude > 0) { - /* If applicable... */ - if (num / magnitude != 0) { - /* Add space */ - if (started == 1) { - append_cstr_to_chain(chain, ", "); - } else { - started = 1; - } - - /* Add triple to chain */ - append_triple_to_chain(chain, num / magnitude); - - /* If in 1000's, million's, etc's place ... */ - if (magnitude != 1) { - /* Append a space, and an appropriate power-of-thousand modifier */ - append_cstr_to_chain(chain, " "); - num_to_cstr(temp, magnitude); - append_cstr_to_chain(chain, temp); - } - } - - /* Reduce number and magnitude */ - num -= (num / magnitude) * magnitude; - magnitude /= 1000; - } -} - -void append_fraction_to_chain(Chain * chain, Fraction fraction) -{ - /* Reduce fraction */ - reduce_fraction(&fraction); - - /* Append "negative" if necessary */ - if (fraction.num < 0) { - append_cstr_to_chain(chain, "negative "); - /* Make numerator positive */ - fraction.num = -fraction.num; - /* Check if zero */ - } else if (fraction.num == 0) { - append_cstr_to_chain(chain, "zero"); - return; - } - /* Check if infinity */ - if (fraction.den == 0) { - append_cstr_to_chain(chain, "a lot"); - return; - } - - - /* Write numerator to chain */ - append_fraction_int_to_chain(chain, fraction.num); - - /* Write denominator to chain */ - if (fraction.den != 1) { - append_cstr_to_chain(chain, " over "); - append_fraction_int_to_chain(chain, fraction.den); - } -} - -Fraction chain_to_fraction(Chain chain) -{ - /* Define starting fraction */ - Fraction frac = construct_fraction(0, 0); - - char value; - Link *it = chain.start; - - int place = 0; - int negative = 0; - - /* Check for negatives */ - if (it != NULL) { - if ('-' == (char) (it->value.num / it->value.den)) { - negative = 1; - it = it->next; - } - - /* Parse chain */ - while (it != NULL) { - /* convert value to character */ - value = (char) (it->value.num / it->value.den); - - /* parse digit */ - if (value >= '0' && value <= '9') { - if (!place) { - /* Add to numerator */ - frac.num *= 10; - frac.num += value - '0'; - } else { - /* Add integer */ - frac.den *= 10; - frac.den += value - '0'; - } - } else if (value == '/' && place == 0) { - place = 1; - } else { - /* Break if coming across an unexpected character */ - break; - } - /* Forward iterator */ - it = it->next; - } - } - - /* Construct, */ - if (place == 0) { - frac.den = 1; - } - if (negative) { - frac.num = -frac.num; - } - - /* 0/0 is 1 in this case */ - if (frac.num == 0 && frac.den == 0) { - frac.num = frac.den = 1; - } - - /* Reduce and return */ - reduce_fraction(&frac); - return frac; -} - - -void write_chain_to_file(Chain chain, Chain filename_as_chain) -{ - // Convert chain to char* - const int max_filename_size = filename_as_chain.length; - char * filename = (char*)malloc(sizeof(char*) * (max_filename_size + 1)); - if(filename == NULL) - { - runtime_error("Couldn't allocate memory for filename buffer in write_chain_to_file"); - } - memset(filename, 0x00, max_filename_size); - const int size = chain_to_cstr(filename_as_chain, filename); - if(size > max_filename_size) - { - runtime_error("Size is ridiculous is write_chain_to_file"); - } - - // Open the file for writing - FILE* fp = fopen(filename, "wb"); - if(fp == NULL) - { - runtime_error("Could not open file %s for writing", filename); - } - - // Write - Link * it = chain.start; - while(it != NULL) - { - fputc((char)(it->value.num/it->value.den), fp); - it = it->next; - } - - fclose(fp); -} -void read_file_to_chain(Chain * chain, Chain filename_as_chain) -{ - // Convert chain to char* - const int max_filename_size = filename_as_chain.length; - char * filename = (char*)malloc(sizeof(char*) * (max_filename_size + 1)); - if(filename == NULL) - { - runtime_error("Couldn't allocate memory for filename buffer in read_chain_to_file"); - } - memset(filename, 0x00, max_filename_size); - const int size = chain_to_cstr(filename_as_chain, filename); - if(size > max_filename_size) - { - runtime_error("Size is ridiculous is read_file_to_chain"); - } - - // Open the file for reading - FILE* fp = fopen(filename, "rb"); - if(fp == NULL) - { - runtime_error("Could not open file %s for reading", filename); - } - - // Read - while(1) - { - char c = (char)fgetc(fp); - if(c == EOF) break; - append_flink_to_chain(chain, construct_fraction(c, 1)); - } - - fclose(fp); - return; -} - -int compare_chains(Chain a, Chain b) -{ - Link *a_iterator = a.start; - Link *b_iterator = b.start; - - /* Compare until at least one node is NULL */ - while (a_iterator != NULL && b_iterator != NULL) { - /* Compare the numerator and denominator */ - if (a_iterator->value.num != b_iterator->value.num - || a_iterator->value.den != b_iterator->value.den) { - return 1; - } - - /* Foward iterators */ - a_iterator = a_iterator->next; - b_iterator = b_iterator->next; - } - - /* Check if one XOR the other is NULL */ - if ((a_iterator == NULL || b_iterator == NULL) - && a_iterator != b_iterator) { - return 1; - } - - return 0; -} - - -/* -void print_chain_numerically(Chain chain) -{ - Link *it = chain.start; - printf("("); - while (it != NULL) { - // Display item numerator as integer - printf("%s%" FRACTION_INT_FORMATTER, - it != chain.start ? ", " : "", it->value.num); - - // Display denominator if not 1 - if (it->value.den != 1) { - printf("/%" FRACTION_INT_FORMATTER, it->value.den); - } - - // Forward iterator - it = it->next; - } - printf(")"); -} -*/ - -FILE* open_file_as_stream(Chain filename, const char* mode) -{ - int max_size = sizeof(char)*(filename.length+1); - char* buffer = (char*)malloc(max_size); - if(filename.length == 0 || buffer == NULL) - { - runtime_error("Could not allocate buffer for file"); - } - - int actual_size = chain_to_cstr(filename, buffer); - if(actual_size > filename.length || actual_size <= 0) - { - runtime_error("Something's terribly wrong in open_file_as_stream"); - } - - FILE* fp = fopen(buffer, mode); - if(fp == NULL){ - perror("perror result: "); - runtime_error("Could not open file %s", buffer); - } - return fp; -} - diff --git a/fetishes/obedience/source/fileio.c b/fetishes/obedience/source/fileio.c new file mode 100644 index 0000000..e1d1d9b --- /dev/null +++ b/fetishes/obedience/source/fileio.c @@ -0,0 +1,99 @@ +#include "core/include/chain.h" +#include "core/include/error.h" +#include "obedience/include/fileio.h" +#include +#include +#include + +void write_chain_to_file(Chain chain, Chain filename_as_chain) +{ + // Convert chain to char* + const int max_filename_size = filename_as_chain.length; + char * filename = (char*)malloc(sizeof(char*) * (max_filename_size + 1)); + if(filename == NULL) + { + runtime_error("Couldn't allocate memory for filename buffer in write_chain_to_file"); + } + memset(filename, 0x00, max_filename_size); + const int size = chain_to_cstr(filename_as_chain, filename); + if(size > max_filename_size) + { + runtime_error("Size is ridiculous is write_chain_to_file"); + } + + // Open the file for writing + FILE* fp = fopen(filename, "wb"); + if(fp == NULL) + { + runtime_error("Could not open file %s for writing", filename); + } + + // Write + Link * it = chain.start; + while(it != NULL) + { + fputc((char)(it->value.num/it->value.den), fp); + it = it->next; + } + + fclose(fp); +} + +void read_file_to_chain(Chain * chain, Chain filename_as_chain) +{ + // Convert chain to char* + const int max_filename_size = filename_as_chain.length; + char * filename = (char*)malloc(sizeof(char*) * (max_filename_size + 1)); + if(filename == NULL) + { + runtime_error("Couldn't allocate memory for filename buffer in read_chain_to_file"); + } + memset(filename, 0x00, max_filename_size); + const int size = chain_to_cstr(filename_as_chain, filename); + if(size > max_filename_size) + { + runtime_error("Size is ridiculous is read_file_to_chain"); + } + + // Open the file for reading + FILE* fp = fopen(filename, "rb"); + if(fp == NULL) + { + runtime_error("Could not open file %s for reading", filename); + } + + // Read + while(1) + { + char c = (char)fgetc(fp); + if(c == EOF) break; + append_flink_to_chain(chain, construct_fraction(c, 1)); + } + + fclose(fp); + return; +} + +FILE* open_file_as_stream(Chain filename, const char* mode) +{ + int max_size = sizeof(char)*(filename.length+1); + char* buffer = (char*)malloc(max_size); + if(filename.length == 0 || buffer == NULL) + { + runtime_error("Could not allocate buffer for file"); + } + + int actual_size = chain_to_cstr(filename, buffer); + if(actual_size > filename.length || actual_size <= 0) + { + runtime_error("Something's terribly wrong in open_file_as_stream"); + } + + FILE* fp = fopen(buffer, mode); + if(fp == NULL){ + perror("perror result: "); + runtime_error("Could not open file %s", buffer); + } + return fp; +} + diff --git a/fetishes/obedience/tests/fileio.cpp b/fetishes/obedience/tests/fileio.cpp new file mode 100644 index 0000000..0521b8f --- /dev/null +++ b/fetishes/obedience/tests/fileio.cpp @@ -0,0 +1,41 @@ +#include "catch.hpp" +#include "core/include/chain.h" +#include "obedience/include/fileio.h" +#include "FileUtil.h" +#include +TEST_CASE("Fileio Test", "[stream][file][obedience]"){ + const char*const sample_text = "A human has fallen from\n\t the surface world\n"; + const char*const sample_text2 = "Mama's scary; Mama hates\t\nyou\n"; + const char*const sample_text3 = "Welcome home, dear friends, how long we've all been waiting\n"; + const char*const sample_text4 = "I am the mastermind; he's my apprentice.\nYou're only still alive because I made a promise\n"; + SECTION("FILE IO") + { + std::string filename = "/tmp/boop2.txt"; + FileUtil::setFileContents(filename, sample_text4); + REQUIRE(FileUtil::getFileContents(filename) == sample_text4); + + Chain filename_as_chain; + init_chain(&filename_as_chain); + append_cstr_to_chain(&filename_as_chain, filename.c_str()); + + Chain chain; + init_chain(&chain); + REQUIRE(chain.length == 0); + + FILE* stream = open_file_as_stream(filename_as_chain, "r+b"); + append_stream_to_chain(&chain, stream); + REQUIRE(chain.length == strlen(sample_text4)); + clear_chain(&chain); + append_cstr_to_chain(&chain, sample_text); + append_chain_to_stream(chain, stream); + clear_chain(&chain); + append_stream_to_chain(&chain, stream); + REQUIRE(chain.length== strlen(sample_text)+strlen(sample_text4)); + + fclose(stream); + clear_chain(&chain); + clear_chain(&filename_as_chain); + + } + +} diff --git a/fetishes/obedience/unit.fet b/fetishes/obedience/unit.fet index 08bbf62..39e667c 100644 --- a/fetishes/obedience/unit.fet +++ b/fetishes/obedience/unit.fet @@ -1,93 +1,5 @@ (I have a fetish for assertiveness) - -(numbers as numbers, oh wee wow) -lick 0 zero times -lick 1 one time -lick 2 two times -lick 3 three times -lick 4 four times -lick 5 five times -lick 6 six times -lick 7 seven times - -(Test Lick) -Lick Alice five times -Lick Bob four times -Lick Charlie four times -have Alice assert dominance over Bob -Have Bob assert equality with Charlie - -(reset) -worship Alice zero times -worship Bob zero times -worship Charlie zero times - -(Test Spank) -Spank Alice five times (should be -5) -Spank Bob four times (should be -4) -Spank Charlie four times (should be -4) -have Bob assert dominance over Alice (-4 > -5) -Have Bob assert equality with Charlie - -(reset) -worship Alice zero times -worship Bob zero times -worship Charlie zero times - -(Test Worship) -spank Alice five times -worship Alice five times -spank Bob twenty five times -Have Bob assert equality with Alice - -(reset) -worship Alice zero times -worship Bob zero times -worship Charlie zero times - -(Test Flog) -have alice assert equality with 0 -flog alice nine times -have alice assert equality with 0 -lick alice one hundred times -flog alice twenty times -have alice assert equality with 5 - -(reset) -worship Alice zero times -worship Bob zero times -worship Charlie zero times - -(Test tickle) -lick Alice two hundred and three times -lick Bob five times -lick Charlie three times -have Bob tickle Alice -have Alice assert equality with Charlie - -(general bind test) -lick count zero times -make chain moan "012" -bind reference to chain - spank reference forty eight times - if count is 0 - have reference assert equality with 0 - if count is 1 - have reference assert equality with 1 - if count is 2 - have reference assert equality with 2 - lick count -have reference assert equality with 0 - -(Chain has been reduced now - so same test without subtracting) -bind reference to chain - if count is 0 - have reference assert equality with 0 - if count is 1 - have reference assert equality with 1 - if count is 2 - have reference assert equality with 2 - lick count +(I have a fetish for obedience) (file handling) make hello moan "That's *burp* right\nthey blew up\n" @@ -107,19 +19,5 @@ have hello tie up goodbye have hello tie up fp have fp assert equality with goodbye - - -(Some comparison) -make flappy moan -make floppy moan -if flappy is not floppy: - make Dungeon Master scream "Empty chains failed to be compared as equivalent" - call safeword - (Finish) -make slave scream "Core unit test completed" - -(Make sure safeword breaks away) -call safeword -make Dungeon Master scream "Safeword was not obeyed" -have 0 assert equality with 1 +make slave scream "Obedience unit test completed" diff --git a/scripts/fetlang_reference_make.py b/scripts/fetlang_reference_make.py index e087e9f..44166d5 100755 --- a/scripts/fetlang_reference_make.py +++ b/scripts/fetlang_reference_make.py @@ -73,7 +73,9 @@ def makeReferencePage(fetish_name): return filename def getShortDescription(fetish): descriptions = {"core" : "The included-by-default fetish that defines the language", - "assertiveness": "Assert operations"} + "assertiveness": "Assert operations", + "obedience": "File interaction"} + return descriptions[fetish] def makeReferencePages(): diff --git a/src/meson.build b/src/meson.build index ea94b8a..0a12bd1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -24,8 +24,9 @@ common_sources = boost_sources+['Fraction.cpp', 'FractionParser.cpp', 'QuoteUtil release_sources = common_sources + ['main.cpp'] fetish_sources = [ -'../fetishes/core/source/chain.c', '../fetishes/core/source/error.c', '../fetishes/core/source/fraction.c', '../fetishes/core/source/fraction_math.c', -'../fetishes/core/tests/chain.cpp'] +'../fetishes/core/source/chain.c', '../fetishes/core/source/error.c', '../fetishes/core/source/fraction.c', +'../fetishes/core/source/fraction_math.c','../fetishes/obedience/source/fileio.c', +'../fetishes/core/tests/chain.cpp', '../fetishes/obedience/tests/fileio.cpp'] test_sources = common_sources + fetish_sources + ['tests/main.cpp','tests/fraction_parser.cpp','tests/quote_util.cpp', 'tests/parser.cpp', 'tests/tokenizer.cpp', 'tests/file_util.cpp', 'tests/compilation.cpp']