From 336024bae94ba163a5a16c74dbf1caefb3b0ebf1 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Sun, 2 Mar 2014 14:44:24 -0500 Subject: [PATCH] file: Update design and create a new unit test Signed-off-by: Anna Schumaker --- DESIGN | 24 ++-- config | 1 + include/file.h | 3 +- lib/file.cpp | 94 ++++++-------- tests/Sconscript | 27 ++-- tests/_functions | 49 ++++++-- tests/file | 113 +++++++++++++++++ tests/file/Sconscript | 6 - tests/file/file.cpp | 287 ------------------------------------------ tests/file/file.good | 86 ------------- tests/src/Sconscript | 10 +- tests/src/file.cpp | 150 ++++++++++++++++++++++ tests/src/version | Bin 14213 -> 0 bytes 13 files changed, 373 insertions(+), 477 deletions(-) create mode 100755 tests/file delete mode 100644 tests/file/Sconscript delete mode 100644 tests/file/file.cpp delete mode 100644 tests/file/file.good create mode 100644 tests/src/file.cpp delete mode 100755 tests/src/version diff --git a/DESIGN b/DESIGN index 457cdb68..84ed1190 100644 --- a/DESIGN +++ b/DESIGN @@ -132,18 +132,13 @@ Callbacks: (lib/callback.cpp) On-disk files: (lib/file.cpp) Data will be stored in the user's home directory according to the - XDG / freedesktop.org specification. This means storing data in - $XDG_DATA_HOME/ocarina{-debug|-test}/ and storing configuration in - $XDG_CONFIG_HOME/ocarina{-debug|-test}/. In addition, I will support - importing data from Ocarina 5.10 for conversion to the new format. + XDG / freedesktop.org specification. This means data will be stored + in a subdirectory of $XDG_DATA_HOME. - In theory my file format will not change often, so it should be - possible to use multiple Ocarina versions with the same data. However, - should the format need to change I will only support forward - compatibility. This means that downgrades will not be possible after - a file format change. To keep the code even cleaner, I will only - support updating from the previous file format version. This means - that legacy support will be removed after the first file format change. + The filse class will support reading and writing files in the users + $XDG_CONFIG_HOME/ocarina{-debug|test}. In addition, Ocarina 6.0 will + support reading library files from the Ocarina 5.10 directory: + $HOME/.ocarina{-debug}. Items should be written to a file with either a space or new line separating multiple values. @@ -156,7 +151,6 @@ On-disk files: (lib/file.cpp) - Hint where the file is located: enum FileLocHint { - FILE_TYPE_CONFIG, FILE_TYPE_DATA, FILE_TYPE_LEGACY, FILE_TYPE_INVALID, @@ -195,9 +189,9 @@ On-disk files: (lib/file.cpp) - API: File :: File(string filepath, FileLocHint hint); Resolve filepath to one of: - XDG_{CONFIG|DATA}_HOME/ocarina/filepath - XDG_{CONFIG|DATA}_HOME/ocarina-debug/filepath - XDG_{CONFIG|DATA}_HOME/ocarina-test/filepath + XDG_DATA_HOME/ocarina/filepath + XDG_DATA_HOME/ocarina-debug/filepath + XDG_DATA_HOME/ocarina-test/filepath $HOME/.ocarina/ $HOME/.ocarina-debug/ $HOME/.ocarina-test/ diff --git a/config b/config index 59d97fb3..d5e5ef0e 100644 --- a/config +++ b/config @@ -26,6 +26,7 @@ Export("env", "use_package", "CONFIG_DEBUG", "CONFIG_VERSION") include = SConscript("include/Sconscript") lib = SConscript("lib/Sconscript") +Export("lib") tests = SConscript("tests/Sconscript") diff --git a/include/file.h b/include/file.h index f71601c8..669912aa 100644 --- a/include/file.h +++ b/include/file.h @@ -10,7 +10,6 @@ #define FILE_VERSION 0 enum FileLocHint { - FILE_TYPE_CONFIG, FILE_TYPE_DATA, FILE_TYPE_LEGACY, FILE_TYPE_INVALID, @@ -29,7 +28,7 @@ private: std::string filepath; unsigned int version; - void find_dir(std::string &); + std::string find_dir(); void open_read(); void open_write(); diff --git a/lib/file.cpp b/lib/file.cpp index a75e8755..0cb20c1b 100644 --- a/lib/file.cpp +++ b/lib/file.cpp @@ -15,49 +15,16 @@ #define OCARINA_DIR "ocarina" #endif -void File :: find_dir(std::string &res) -{ - if (hint == FILE_TYPE_INVALID) - return; - - switch (hint) { - case FILE_TYPE_CONFIG: - res = g_get_user_config_dir(); - break; - case FILE_TYPE_DATA: - res = g_get_user_data_dir(); - break; - default: /* FILE_TYPE_LEGACY */ - res = g_get_home_dir(); - break; - } - - res += "/"; - switch (hint) { - case FILE_TYPE_CONFIG: - case FILE_TYPE_DATA: - res += OCARINA_DIR; - break; - default: /* FILE_TYPE_LEGACY */ - res += "."; - res += OCARINA_DIR; - res += "/library"; - } -} - File :: File(const std::string &path, FileLocHint file_hint) - : mode(NOT_OPEN), hint(file_hint) + : mode(NOT_OPEN), hint(file_hint), version(FILE_VERSION) { - std::string dir; - - if (path == "") { + if (path.size() == 0) hint = FILE_TYPE_INVALID; - filepath = "INVALID"; - return; - } - find_dir(dir); - filepath = dir + "/" + path; + if (hint == FILE_TYPE_INVALID) + filepath = "INVALID"; + else + filepath = find_dir() + "/" + path; } File :: ~File() @@ -80,16 +47,34 @@ bool File :: exists() return g_file_test(filepath.c_str(), G_FILE_TEST_EXISTS); } +std::string File :: find_dir() +{ + std::string res; + + if (hint == FILE_TYPE_DATA) { + res = g_get_user_data_dir(); + res += "/"; + res += OCARINA_DIR; + } else /* FILE_TYPE_LEGACY */ { + res = g_get_home_dir(); + res += "/."; + res += OCARINA_DIR; + res += "/library"; + } + + return res; +} + void File :: open_read() { if (!exists()) { - dprint("ERROR: File does not exist (%s)\n", filepath.c_str()); + dprint("ERROR: File does not exist\n"); throw -E_EXIST; } std::fstream::open(filepath.c_str(), std::fstream::in); if (std::fstream::fail()) { - dprint("ERROR: Could not open file for reading (%s)\n", filepath.c_str()); + dprint("ERROR: File could not be opened for reading\n"); throw -E_IO; } @@ -100,21 +85,20 @@ void File :: open_read() void File :: open_write() { - std::string dir; if (hint == FILE_TYPE_LEGACY) { - dprint("ERROR: Cannot write to legacy files (%s)\n", filepath.c_str()); + dprint("ERROR: Cannot write to legacy files\n"); throw -E_IO; } - find_dir(dir); + std::string dir = find_dir(); if (g_mkdir_with_parents(dir.c_str(), 0755) != 0) { - dprint("ERROR: Could not make directory (%s)\n", dir.c_str()); + dprint("ERROR: Could not make directory\n"); throw -E_IO; } std::fstream::open(filepath.c_str(), std::fstream::out); if (std::fstream::fail()) { - dprint("ERROR: Could not open file for writing (%s)\n", filepath.c_str()); + dprint("ERROR: Could not open file for writing\n"); throw -E_IO; } @@ -124,18 +108,18 @@ void File :: open_write() void File :: open(OpenMode m) { - if (mode != NOT_OPEN) { - dprint("ERROR: File is already open (%s)\n", filepath.c_str()); + if (hint == FILE_TYPE_INVALID) { + dprint("ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened\n"); + throw -E_INVAL; + } else if (m == NOT_OPEN) { + dprint("ERROR: NOT_OPEN is not a legal OpenMode\n"); + throw -E_INVAL; + } else if (mode != NOT_OPEN) { + dprint("ERROR: File is already open\n"); throw -E_IO; } - if (m == NOT_OPEN) { - dprint("ERROR: NOT_OPEN is not a legal OpenMode (%s)\n", filepath.c_str()); - throw -E_INVAL; - } else if (hint == FILE_TYPE_INVALID) { - dprint("ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened\n"); - throw -E_INVAL; - } else if (m == OPEN_READ) + else if (m == OPEN_READ) open_read(); else /* m == OPEN_WRITE */ open_write(); diff --git a/tests/Sconscript b/tests/Sconscript index 8567594a..f7413fc9 100644 --- a/tests/Sconscript +++ b/tests/Sconscript @@ -1,21 +1,20 @@ #!/usr/bin/python Import("env") +env.Append( CCFLAGS = [ "-DCONFIG_TEST" ] ) src = SConscript("src/Sconscript") -tests = [ "version" ] - - -def Test(name): - return Command("%s.out" % name, [], "./tests/%s" % name) - -for test in tests: - t = Test(test) - Depends(t, src) - AlwaysBuild(t) - -#AlwaysBuild(test) -#Depends(test, src) - +tests = [ "version", "file" ] #scripts = [ "print", "file", "database", "index", "filter", "idle", "playlist", # "library", "playqueue", "deck", "audio", "gui" ] + +prev = None + +for test in tests: + t = Command("%s.out" % test, [], "./tests/%s" % test) + + if prev: + Depends(t, prev) + Depends(t, src) + AlwaysBuild(t) + prev = t diff --git a/tests/_functions b/tests/_functions index fd4e3643..4755bf77 100644 --- a/tests/_functions +++ b/tests/_functions @@ -16,18 +16,51 @@ function config_debug read_config CONFIG_DEBUG } -function test_success +CUR_TEST=0 +function new_test { - echo "Success!" - exit 0 + echo "$1" + CUR_TEST=0 } -function test_failed +function start_test { - echo "FAILED =(" - on_failed - exit 1 + echo -n " $CUR_TEST: " + let CUR_TEST=($CUR_TEST + 1) } +function assert_equal +{ + if [ "$1" == "$2" ]; then + echo "Success!" + return 0 + else + echo "FAILED =(" + echo " Expected: $2" + echo " Actual: $1" + return 1 + fi +} + +function test_equal +{ + start_test + assert_equal "$($1)" "$2" +} + +function on_exit +{ + ret=$? + echo + return $ret +}; trap "on_exit" EXIT + +[ -z $HOME ] && HOME=$(cat /etc/passwd | grep $(whoami) | awk -F: '{print $6}') +[ -z $XDG_DATA_HOME] && XDG_DATA_HOME="$HOME/.local/share" +DATA_DIR="$XDG_DATA_HOME/ocarina-test" +LEGACY_DIR="$HOME/.ocarina-test/library" + +rm -rf $DATA_DIR 2>/dev/null || true + +set -e cd $(dirname $0) -echo -n "Testing $(basename $0) ... " diff --git a/tests/file b/tests/file new file mode 100755 index 00000000..3c3c5567 --- /dev/null +++ b/tests/file @@ -0,0 +1,113 @@ +#!/bin/bash +# Copyright 2014 (c) Anna Schumaker + +. $(dirname $0)/_functions + +function test_file +{ + test_equal "./src/file $1" "$2" +} + + + +### +# +# Test filepaths +# + +new_test "Filepath Test" + +test_file -D INVALID +test_file -L INVALID +test_file "-D file.txt" "$DATA_DIR/file.txt" +test_file "-L file.txt" "$LEGACY_DIR/file.txt" +test_file "file.txt" INVALID +test_file "-D -v file.txt" "0" +test_file "-L -v file.txt" "0" + +if [ -d $DATA_DIR ]; then + echo "ERROR: $DATA_DIR should not exist!" + exit 1 +fi + + + +### +# +# Test opening files +# + +echo +new_test "File Open Test" + +# Generic open testing +test_file "-o N file.txt" "ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened" +test_file "-D -o N file.txt" "ERROR: NOT_OPEN is not a legal OpenMode" +test_file "-D -o W -O file.txt" "ERROR: File is already open" # This test creates a file +test_file "-D -o R -O file.txt" "ERROR: File is already open" +rm $DATA_DIR/* + +# Test opening for read +test_file "-D -o R file.txt" "ERROR: File does not exist" + +touch $DATA_DIR/file.txt +chmod -r $DATA_DIR/file.txt +test_file "-D -o R file.txt" "ERROR: File could not be opened for reading" +rm -r $DATA_DIR + +# Test opening for write +test_file "-L -o W file.txt" "ERROR: Cannot write to legacy files" + +touch $DATA_DIR +test_file "-D -o W file.txt" "ERROR: Could not make directory" + +rm $DATA_DIR +mkdir -p $DATA_DIR +touch $DATA_DIR/file.txt +chmod -w $DATA_DIR/file.txt +test_file "-D -o W file.txt" "ERROR: Could not open file for writing" +rm -rf $DATA_DIR + + + +### +# +# Test closing files +# + +echo +new_test "File Close Test" +test_file "-D -c file.txt" "" + + + +### +# +# Test FILE IO +# + +data="ABCDE FGHIJ KLMNO PQRST UVWXYZ" +echo +new_test "File IO Test" + +# Write to file +./src/file -D -w file.txt "$data" +start_test +assert_equal "$(cat $DATA_DIR/file.txt)" "0 +$data" + +# Read data back from file +test_file "-D -r file.txt" "ABCDE +FGHIJ +KLMNO +PQRST +UVWXYZ" + +# Write different data to file +./src/file -D -w file.txt " $data" +start_test +assert_equal "$(cat $DATA_DIR/file.txt)" "0 + $data" + +# Read data back in a single line +test_file "-D -r -g file.txt" "$data" diff --git a/tests/file/Sconscript b/tests/file/Sconscript deleted file mode 100644 index a31ddf89..00000000 --- a/tests/file/Sconscript +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/python -Import("Test", "CONFIG") - -CONFIG.FILE = True - -Test("file", "file.cpp") diff --git a/tests/file/file.cpp b/tests/file/file.cpp deleted file mode 100644 index 7f005b41..00000000 --- a/tests/file/file.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2013 (c) Anna Schumaker. - */ -#include -#include -#include - -#include - -bool test_result(bool passed, bool print_spaces) -{ - if (print_spaces) - print(" "); - if (passed == true) - print("Passed\n"); - else - print("Failed\n"); - return passed; -} - -File *get_file(int testno, char subtest, bool valid, FileLocHint hint) -{ - std::stringstream s; - std::string path = ""; - if (valid == true) { - path = "file."; - s << testno; - path += s.str() + subtest; - } - print("Test %d%c: ", testno, subtest); - return new File(path, hint); -} - -static inline bool inval_or_legacy(bool valid, FileLocHint hint) -{ - return (valid == false) || (hint == FILE_TYPE_LEGACY); -} - -/* - * Check how filepath is expanded - * An empty filepath == INVALID - */ -void test_a(int testno, bool valid, FileLocHint hint) -{ - File *f = get_file(testno, 'a', valid, hint); - print("File path is %s\n", f->get_filepath()); -} - -/* - * NOT_OPEN is not a valid openmode - */ -void test_b(int testno, bool valid, FileLocHint hint) -{ - int status = 0; - File *f = get_file(testno, 'b', valid, hint); - try { - f->open(NOT_OPEN); - } catch (int error) { - status = error; - } - test_result(status == -E_INVAL, true); -} - -/* - * If a file doesn't exist, it can't be opened for reading - */ -void test_c(int testno, bool valid, FileLocHint hint) -{ - int status = 0; - File *f = get_file(testno, 'c', valid, hint); - try { - f->open(OPEN_READ); - } catch (int error) { - status = error; - } - if (valid == false) - test_result(status == -E_INVAL, true); - else - test_result(status == -E_EXIST, true); -} - -/* - * Writing to FILE_TYPE_LEGACY is not supported - */ -void test_d(int testno, bool valid, FileLocHint hint) -{ - int status = 0; - File *f = get_file(testno, 'd', valid, hint); - - try { - f->open(OPEN_WRITE); - } catch (int error) { - status = error; - } - - if (valid == false) - test_result(status == -E_INVAL, true); - else if (hint == FILE_TYPE_LEGACY) - test_result(status == -E_IO, true); - else - test_result(status == 0, false); -} - -/* - * Attempt to close a file that was never opened - */ -void test_e(int testno, bool valid, FileLocHint hint) -{ - int status = 0; - File *f = get_file(testno, 'e', valid, hint); - try { - f->close(); - } catch (int error) { - status = error; - } - test_result(status == 0, false); -} - -/* - * Open for writing, then for reading - */ -void test_f(int testno, bool valid, FileLocHint hint) -{ - File *f; - int status = 0; - - if (inval_or_legacy(valid, hint)) - return; - - f = get_file(testno, 'f', valid, hint); - - try { - f->open(OPEN_WRITE); - } catch (int error) { - status = error; - } - test_result(status == 0, false); - print(" "); - - status = 0; - try { - f->open(OPEN_READ); - } catch (int error) { - status = error; - } - test_result(status == -E_IO, true); -} - -/* - * Create a file, then open for reading - */ -void test_g(int testno, bool valid, FileLocHint hint) -{ - File *f; - int status = 0; - - if (inval_or_legacy(valid, hint)) - return; - - f = get_file(testno, 'g', valid, hint); - - try { - f->open(OPEN_WRITE); - } catch (int error) { - status = error; - } - if (!test_result(status == 0, false)) - return; - - try { - f->close(); - } catch (int error) { - status = error; - } - if (!test_result(status == 0, true)) - return; - - try { - f->open(OPEN_READ); - } catch (int error) { - status = error; - } - if (!test_result(status == 0, true)) - return; - - f->close(); -} - -/* - * Test doing IO to a file - */ -void test_h(int testno, bool valid, FileLocHint hint) -{ - File *f; - int a, b, c, d, e, status = 0; - - if (inval_or_legacy(valid, hint)) - return; - f = get_file(testno, 'h', valid, hint); - - /* - * Write data to file - */ - try { - f->open(OPEN_WRITE); - } catch (int error) { - status = error; - } - if (!test_result(status == 0, false)) - return; - - (*f) << "Hello, World!" << std::endl; - (*f) << "This is a multi-line file =)" << std::endl; - (*f) << "1 2 3 4 5" << std::endl; - - try { - f->close(); - } catch (int error) { - status = error; - } - if (!test_result(status == 0, true)) - return; - - /* - * Read data back from disk - */ - try { - f->open(OPEN_READ); - } catch (int error) { - status = error; - } - if (!test_result(status == 0, true)) - return; - - print(" File version is: %u\n", f->get_version()); - print(" \"%s\"\n", f->getline().c_str()); - if (!test_result(f->good(), true)) - return; - print(" \"%s\"\n", f->getline().c_str()); - if (!test_result(f->good(), true)) - return; - - (*f) >> a >> b >> c >> d >> e; - if (!test_result(f->good(), true)) - return; - print(" a: %d, b: %d, c: %d, d: %d, e: %d\n", a, b, c, d, e); - - /* - * Close file - */ - try { - f->close(); - } catch (int error) { - status = error; - } - test_result(status == 0, true); -} - -static void(*tests[])(int, bool, FileLocHint) = { - test_a, - test_b, - test_c, - test_d, - test_e, - test_f, - test_g, - test_h, -}; -static unsigned int num_tests = sizeof(tests) / sizeof(void (*)(int, bool, FileLocHint)); - -void run_test(int testno, bool valid, FileLocHint hint) -{ - for (unsigned int i = 0; i < num_tests; i++) - tests[i](testno, valid, hint); - print("\n"); -} - -int main(int argc, char **argv) -{ - run_test(1, true, FILE_TYPE_CONFIG); - run_test(2, false, FILE_TYPE_CONFIG); - run_test(3, true, FILE_TYPE_DATA); - run_test(4, false, FILE_TYPE_DATA); - run_test(5, true, FILE_TYPE_LEGACY); - run_test(6, false, FILE_TYPE_LEGACY); - return 0; -} diff --git a/tests/file/file.good b/tests/file/file.good deleted file mode 100644 index 242afab3..00000000 --- a/tests/file/file.good +++ /dev/null @@ -1,86 +0,0 @@ -Test 1a: File path is /home/anna/.config/ocarina-test/file.1a -Test 1b: ERROR: NOT_OPEN is not a legal OpenMode (/home/anna/.config/ocarina-test/file.1b) - Passed -Test 1c: ERROR: File does not exist (/home/anna/.config/ocarina-test/file.1c) - Passed -Test 1d: Passed -Test 1e: Passed -Test 1f: Passed - ERROR: File is already open (/home/anna/.config/ocarina-test/file.1f) - Passed -Test 1g: Passed - Passed - Passed -Test 1h: Passed - Passed - Passed - File version is: 0 - "Hello, World!" - Passed - "This is a multi-line file =)" - Passed - Passed - a: 1, b: 2, c: 3, d: 4, e: 5 - Passed - -Test 2a: File path is INVALID -Test 2b: ERROR: NOT_OPEN is not a legal OpenMode (INVALID) - Passed -Test 2c: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened - Passed -Test 2d: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened - Passed -Test 2e: Passed - -Test 3a: File path is /home/anna/.local/share/ocarina-test/file.3a -Test 3b: ERROR: NOT_OPEN is not a legal OpenMode (/home/anna/.local/share/ocarina-test/file.3b) - Passed -Test 3c: ERROR: File does not exist (/home/anna/.local/share/ocarina-test/file.3c) - Passed -Test 3d: Passed -Test 3e: Passed -Test 3f: Passed - ERROR: File is already open (/home/anna/.local/share/ocarina-test/file.3f) - Passed -Test 3g: Passed - Passed - Passed -Test 3h: Passed - Passed - Passed - File version is: 0 - "Hello, World!" - Passed - "This is a multi-line file =)" - Passed - Passed - a: 1, b: 2, c: 3, d: 4, e: 5 - Passed - -Test 4a: File path is INVALID -Test 4b: ERROR: NOT_OPEN is not a legal OpenMode (INVALID) - Passed -Test 4c: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened - Passed -Test 4d: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened - Passed -Test 4e: Passed - -Test 5a: File path is /home/anna/.ocarina-test/library/file.5a -Test 5b: ERROR: NOT_OPEN is not a legal OpenMode (/home/anna/.ocarina-test/library/file.5b) - Passed -Test 5c: ERROR: File does not exist (/home/anna/.ocarina-test/library/file.5c) - Passed -Test 5d: ERROR: Cannot write to legacy files (/home/anna/.ocarina-test/library/file.5d) - Passed -Test 5e: Passed - -Test 6a: File path is INVALID -Test 6b: ERROR: NOT_OPEN is not a legal OpenMode (INVALID) - Passed -Test 6c: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened - Passed -Test 6d: ERROR: A file with hint = FILE_TYPE_INVALID cannot be opened - Passed -Test 6e: Passed - diff --git a/tests/src/Sconscript b/tests/src/Sconscript index 7779c018..1e455ebf 100644 --- a/tests/src/Sconscript +++ b/tests/src/Sconscript @@ -1,8 +1,10 @@ #!/usr/bin/python -Import("env") +Import("env", "lib") -def compile_utility(name): - return env.Program(name, "%s.cpp" % name) +build = [] +for f in Glob("*.cpp"): + src = str(f) + name = src.split(".")[0] + build += [ env.Program(name, [src] + lib) ] -build = compile_utility("version") Return("build") diff --git a/tests/src/file.cpp b/tests/src/file.cpp new file mode 100644 index 00000000..24412b11 --- /dev/null +++ b/tests/src/file.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2014 (c) Anna Schumaker. + * Do stuff with files + * + * Usage: files -D|-L [-c -g -o {R, W, N} -O -r -v -w] name [DATA] + * + * -D: FILE_TYPE_DATA + * -L: FILE_TYPE_LEGACY + * + * -c: Test closing the file + * -g: Read file using getline() + * -o: Open the file for READ, WRITE, or NOT_OPEN + * -O: Open the file a second time + * -r: Read data from file + * -v: Print version and exit + * -w: Write data to file + * + */ +#include +#include + +#include + +enum action_t { CLOSE, OPEN, PATHS, READ, VERSION, WRITE }; + +int print_version(File &f) +{ + print("%u\n", f.get_version()); + return 0; +} + +int print_filepath(File &f) +{ + print("%s\n", f.get_filepath()); + return 0; +} + +int open_file(File &f, OpenMode mode) +{ + try { + f.open(mode); + return 0; + } catch (int err) { + return err; + } +} + +int main(int argc, char **argv) +{ + int c, ret; + action_t action = PATHS; + FileLocHint hint = FILE_TYPE_INVALID; + OpenMode mode = NOT_OPEN; + bool second_open = false; + bool getline = false; + std::string file; + std::string data; + + while ((c = getopt(argc, argv, "cDgLo:Orvw")) != -1) { + switch (c) { + case 'c': + action = CLOSE; + break; + case 'D': + hint = FILE_TYPE_DATA; + break; + case 'g': + getline = true; + break; + case 'L': + hint = FILE_TYPE_LEGACY; + break; + case 'o': + action = OPEN; + switch (optarg[0]) { + case 'R': + mode = OPEN_READ; + break; + case 'W': + mode = OPEN_WRITE; + break; + case 'N': + mode = NOT_OPEN; + break; + default: + print("Invalid open mode\n"); + return 1; + } + break; + case 'O': + second_open = true; + break; + case 'r': + action = READ; + break; + case 'v': + action = VERSION; + break; + case 'w': + action = WRITE; + break; + default: + return 1; + } + } + + if (optind < argc) + file = argv[optind++]; + if (optind < argc) + data = argv[optind++]; + + File f(file, hint); + switch (action) { + case CLOSE: + ret = open_file(f, OPEN_WRITE); + if (ret == 0) { + f.close(); + ret = open_file(f, OPEN_WRITE); + } + return ret; + case OPEN: + ret = open_file(f, mode); + if ((ret == 0) && (second_open == true)) + ret = open_file(f, mode); + return ret; + case PATHS: + return print_filepath(f); + case READ: + ret = open_file(f, OPEN_READ); + if (ret == 0) { + do { + if (getline == true) + data = f.getline(); + else + f >> data; + if (f.good() == false) + break; + print("%s\n", data.c_str()); + } while (true); + } + return ret; + case VERSION: + return print_version(f); + case WRITE: + ret = open_file(f, OPEN_WRITE); + if (ret == 0) + f << data << std::endl; + return ret; + } +} diff --git a/tests/src/version b/tests/src/version deleted file mode 100755 index bede8ee86977a87aa8a8151ab5c1d6c939a35ea8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14213 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