summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ball <nullspoon@iohq.net>2015-02-20 13:56:02 -0700
committerAaron Ball <nullspoon@iohq.net>2015-02-20 13:56:02 -0700
commitcb7c1c8994e0990de338ea789332e347ac14d3eb (patch)
treefadd3fbc0ad552e2327cc4e0cb8e4f90be491e27
parent44d8d50ddf14a6741328a7651e0a5deafc0fa17d (diff)
downloadnoteless-cb7c1c8994e0990de338ea789332e347ac14d3eb.tar.gz
noteless-cb7c1c8994e0990de338ea789332e347ac14d3eb.tar.xz
Implemented config parsing
Created config struct and complimentary functions. Can check if a config variable is set and can get values along with a variable count. Also successfully handles blank (or empty) lines as well as lines that are commented out and lines that have inline comments. Updated main calls to old c++ config class to work with the new c struct and related functions. Moved get_user_editor function into common.c and created appropriate header file.
-rw-r--r--Makefile10
-rw-r--r--src/common.c34
-rw-r--r--src/common.h26
-rw-r--r--src/config.c269
-rw-r--r--src/config.h50
-rw-r--r--src/main.c283
6 files changed, 446 insertions, 226 deletions
diff --git a/Makefile b/Makefile
index b42e1da..a5a4540 100644
--- a/Makefile
+++ b/Makefile
@@ -6,11 +6,13 @@ cc = cc
all:
if [[ ! -d obj ]]; then mkdir obj; fi
- $(cc) $(dbg) $(warnings) -std=$(std) -c src/path.c -o $(obj)path.o
+ $(cc) $(dbg) $(warnings) -std=$(std) -c src/common.c -o $(obj)common.o
+ # $(cc) $(dbg) $(warnings) -std=$(std) -c src/path.c -o $(obj)path.o
$(cc) $(dbg) $(warnings) -std=$(std) -c src/config.c -o $(obj)config.o
- $(cc) $(dbg) $(warnings) -std=$(std) -c src/note.c -o $(obj)note.o
- $(cc) $(dbg) $(warnings) -std=$(std) -c src/note_list.c -o $(obj)note_list.o
- $(cc) $(dbg) $(warnings) -std=$(std) src/main.c $(obj)*.o -o $(out)
+ # $(cc) $(dbg) $(warnings) -std=$(std) -c src/note.c -o $(obj)note.o
+ # $(cc) $(dbg) $(warnings) -std=$(std) -c src/note_list.c -o $(obj)note_list.o
+ # $(cc) $(dbg) $(warnings) -std=$(std) src/main.c $(obj)*.o -o $(out)
+ $(cc) $(dbg) $(warnings) -std=$(std) src/main.c $(obj)/* -o $(out)
debug:
make all dbg="-g"
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 0000000..ad40025
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2015 Aaron Ball <nullspoon@iohq.net>
+ *
+ * Noteless is free software: 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
+ * (at your option) any later version.
+ *
+ * Noteless is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Noteless. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "common.h"
+
+/**
+ * Determins the text editor that should be used. Checks the environmental
+ * variable EDITOR for this.
+ *
+ * @return char* Path to the editor binary to be used (stored in heap)
+ */
+void get_user_editor(char* editor) {
+ if(getenv("EDITOR") != NULL) {
+ /* If the EDITOR variable is set, use that */
+ //int editor_len = strlen(getenv("EDITOR"));
+ // *editor = calloc(editor_len, sizeof(char));
+ strcpy(editor, getenv("EDITOR"));
+ } else {
+ strcpy(editor, "vi");
+ }
+}
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..b11fd8c
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2015 Aaron Ball <nullspoon@iohq.net>
+ *
+ * Noteless is free software: 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
+ * (at your option) any later version.
+ *
+ * Noteless is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with noteless. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef noteless_common
+#define noteless_common
+
+void get_user_editor(char*);
+
+#endif
diff --git a/src/config.c b/src/config.c
index dfb78ca..631b580 100644
--- a/src/config.c
+++ b/src/config.c
@@ -24,83 +24,222 @@
*
* @param const char* p Path to the config file to be read in
*/
-config::config( const char* p ) {
- path = p;
+int config_new(config_t* conf, char* p) {
+ // TODO
+ strcpy(conf->path, p);
- vector<string> lines;
- ifstream fs( path );
+ conf->count = config_valid_line_count(p);
- // Verify the file handle opened sucessfully
- if( ! fs.is_open() ) {
- cout << "Could not open file at " << path << "." << endl;
- exit( 1 );
+ conf->keys = calloc(conf->count, sizeof(char*));
+ conf->values = calloc(conf->count, sizeof(char*));
+
+ FILE* f;
+ f = fopen(conf->path, "r");
+
+ // Verify the file could be opened
+ if(!f) {
+ printf("Could not open config file at %s.\n", conf->path);
+ return -1;
}
- // Continue
- string line;
- while( getline( fs, line ) ) {
- parse_line( line );
+
+ // Set the maximum read width and read buffer array
+ int len = 120;
+ char buf[len];
+
+ char key[32];
+ char value[256];
+
+ int i = 0;
+ while(fgets(buf, len, f) != NULL) {
+ int start = 0;
+ // This loop allows for lines to not start at the beginning
+ while(buf[start] != '\0') {
+ if(buf[start] != ' ') {
+ break;
+ } else {
+ start++;
+ }
+ }
+
+ // Skip all lines starting with a comment char
+ if(buf[start] == '#') { continue; }
+ // Skip empty lines
+ if(buf[start] == '\n') { continue; }
+
+ int end = start;
+ while(buf[end] != '\0') {
+ // This allows for inline comment chars. The line ends when the first
+ // comment char is found.
+ if(buf[end] == '#' || buf[end] == '\n') { break; }
+ end++;
+ }
+
+ char tmp_line[end - start + 10];
+ // Temp variable to store the text between index start and index end
+ strncpy(tmp_line, &buf[start], end - start + 1);
+ // Make sure it has a trailing newline so sscanf works
+ strcat(tmp_line, "\n");
+
+ // Parse the line into temp variables
+ sscanf(tmp_line, "%s %s", key, value);
+
+ // Allocate heap memory for values since these need to persist.
+ // Note that here we are using the temp variables to establish string
+ // length for when we allocate heap memory.
+ conf->keys[i] = malloc(sizeof(char) * strlen(key));
+ conf->values[i] = malloc(sizeof(char) * strlen(value));
+
+ // Copy in the temp values
+ strcpy(conf->keys[i], key);
+ strcpy(conf->values[i], value);
+
+ // Increment the counter for tracking keys and values in their respective
+ // arrays
+ i++;
}
- fs.close();
+
+ fclose(f);
+
+ return 0;
}
+
/**
- * Parses one line of the config file. Strips illegal characters first, then
- * sets key to the text on the left of the equals sign and value to the text on
- * the right.
- *
- * string line - Config file line to be parsed and added to the config object
+ * Destructor for config struct.
*
- * return int Success or failure
+ * @param conf Config_t pointer to be freed from memory
*/
-int config::parse_line( string line ) {
- // The two vars that will be appended to the key value vector
- string key;
- string value;
- int split;
-
- // Clean spaces and other illegal chars
- string clean_line;
- for( int i = 0; i < line.length(); i++ ) {
- if( line[i] == ' ' ) {
- // Ignore, it's a space
- continue;
- } else {
- clean_line += line[i];
- }
+void config_free(config_t* conf) {
+ for(int i = 0; i < conf->count; i++) {
+ free(conf->keys[i]);
+ free(conf->values[i]);
}
+ free(conf->keys);
+ free(conf->values);
+}
- // Line was empty, skip 'er
- if( clean_line.length() == 0 ) { return 0; }
- // One character at a time
- for( int i = 0; i < clean_line.length(); i++ ) {
- if( clean_line[i] == '=' ) {
- // Set the key
- key = clean_line.substr( 0, i );
- split = i;
- break;
- }
+/**
+ * Performs a line count of valid lines in the specified config file. This is
+ * useful for determining the size of an array to store keys or values in.
+ * A valid line is considered to be a line that is not empty or commented out.
+ *
+ * @param path Path to the config file to be parsed
+ *
+ * @return int Count of lines that are not commented out or empty
+ */
+int config_valid_line_count(char* path) {
+ int count = 0;
+
+ FILE* f;
+ f = fopen(path, "r");
+
+ int len = 120;
+ char buf[len];
+
+ while(fgets(buf, len, f) != NULL) {
+ int start = 0;
+
+ // Find the first char
+ while(buf[start] == ' ') { start++; }
+
+ // Confirm the line is not a comment or empty
+ if(buf[start] != '#' && buf[start] != '\n') { count++; }
}
- // Set the value
- value = clean_line.substr( split + 1, clean_line.length() );
+ fclose(f);
+
+ return count;
+}
- // Append to class global values
- values.push_back( key );
- values.push_back( value );
- // Success!
+/**
+ * Checks the configuration struct for the given key's value.
+ *
+ * @param conf Config_t instance pointer containing keys and values to check
+ * @param key Key to check if exists
+ *
+ * @return int Key value exists (1) or not (0)
+ */
+int config_isset(config_t* conf, char* key) {
+ for(int i = 0; i < conf->count; i++) {
+ if(strcmp(conf->keys[i], key) == 0) {
+ return 1;
+ }
+ }
return 0;
}
-bool config::isset( string key ) {
- for( int i = 0; i < values.size(); i+=2 ) {
- if( values[i] == key ) {
- return true;
+/**
+ * TODO
+ */
+char* config_get(config_t* conf, char* key) {
+ for(int i = 0; i < conf->count; i++) {
+ if(strcmp(conf->keys[i], key) == 0) {
+ return conf->values[i];
}
}
- return false;
+ return NULL;
}
+
+/**
+ * Parses one line of the config file. Strips illegal characters first, then
+ * sets key to the text on the left of the equals sign and value to the text on
+ * the right.
+ *
+ * string line - Config file line to be parsed and added to the config object
+ *
+ * return int Success or failure
+ */
+// int config::parse_line( string line ) {
+// // The two vars that will be appended to the key value vector
+// string key;
+// string value;
+// int split;
+//
+// // Clean spaces and other illegal chars
+// string clean_line;
+// for( int i = 0; i < line.length(); i++ ) {
+// if( line[i] == ' ' ) {
+// // Ignore, it's a space
+// continue;
+// } else {
+// clean_line += line[i];
+// }
+// }
+//
+// // Line was empty, skip 'er
+// if( clean_line.length() == 0 ) { return 0; }
+//
+// // One character at a time
+// for( int i = 0; i < clean_line.length(); i++ ) {
+// if( clean_line[i] == '=' ) {
+// // Set the key
+// key = clean_line.substr( 0, i );
+// split = i;
+// break;
+// }
+// }
+// // Set the value
+// value = clean_line.substr( split + 1, clean_line.length() );
+//
+// // Append to class global values
+// values.push_back( key );
+// values.push_back( value );
+//
+// // Success!
+// return 0;
+// }
+
+// bool config::isset( string key ) {
+// for( int i = 0; i < values.size(); i+=2 ) {
+// if( values[i] == key ) {
+// return true;
+// }
+// }
+// return false;
+// }
+
/**
* Returns the value for the specified key
*
@@ -108,13 +247,13 @@ bool config::isset( string key ) {
*
* return string The value of the specified key
*/
-string config::get( string key ) {
- // Hop skip and jump
- // Evens are keys, odds are values (even + 1)
- for( int i = 0; i < values.size(); i+=2 ) {
- if( values[i] == key ) {
- return values[i+1];
- }
- }
- return "Unknown";
-}
+// string config::get( string key ) {
+// // Hop skip and jump
+// // Evens are keys, odds are values (even + 1)
+// for( int i = 0; i < values.size(); i+=2 ) {
+// if( values[i] == key ) {
+// return values[i+1];
+// }
+// }
+// return "Unknown";
+// }
diff --git a/src/config.h b/src/config.h
index 8a52bd7..89d1bdd 100644
--- a/src/config.h
+++ b/src/config.h
@@ -16,35 +16,37 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-using namespace std;
+#ifndef NOTELESS_CONFIG_H
+#define NOTELESS_CONFIG_H
+
#include <stdlib.h>
-#include <iostream>
-#include <vector>
-#include <string>
-#include <fstream>
-#ifndef LIB_CONFIG_H
-#define LIB_CONFIG_H
+#include <stdio.h>
+#include <string.h>
/**
* Represents a config file in memory. Provides a friendly interface for
* checking configuration variables without having to parse multiple times.
*/
-class config {
-public:
- // Class global variables
- vector<string> values;
- const char* path;
-
- // Constructors
- config( const char* );
-
- // Public helper methods
- string get( string );
- bool isset( string );
-
-private:
- // Private helper methods
- int parse_line( string );
-};
+typedef struct config {
+ int count;
+ char path[256];
+ char note_path[256];
+ char extension[16];
+ char** keys;
+ char** values;
+} config_t;
+
+int config_new(config_t*, char*);
+void config_free(config_t*);
+
+int config_isset(config_t*, char*);
+
+char* config_get(config_t*, char*);
+
+int config_valid_line_count(char*);
+
+// get(char*, char*);
+// int isset(char*);
+// int parse_line(char*);
#endif
diff --git a/src/main.c b/src/main.c
index d023ac1..d297aee 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,16 +14,17 @@
* You should have received a copy of the GNU General Public License
* along with noteless. If not, see <http://www.gnu.org/licenses/>.
*/
-using namespace std;
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
+#include "common.h"
#include "config.h"
-#include "note.h"
-#include "note_list.h"
-#include "path.h"
+// #include "note.h"
+// #include "note_list.h"
+// #include "path.h"
int get_help() {
- string out = "\nNoteless provides a simple command line interface for note "
+ char out[] = "\nNoteless provides a simple command line interface for note "
"taking.\n\n"
"What makes this different than simply using a command line text editor is\n"
"there is no need to type paths or file extensions. It handles all of the\n"
@@ -38,154 +39,170 @@ int get_help() {
" given search term.\n"
" help Displays this help text\n"
" ls,list Lists all notes in note directory.\n";
- cout << out << endl;
+ printf("%s\n", out);
return 0;
}
/**
* Prints names of all notes
*/
-void list_notes( note_list list ) {
- // List notes
- vector<string> names = list.enum_names();
- cout << endl;
- for( int i = 0; i < names.size(); i++ ) {
- cout << "* " << names[i] << endl;
- }
- cout << endl;
-}
-
-/**
- * Searches all note contents for the specified text
- */
-int search_notes( note_list list, string term ) {
- vector<string> matches = list.find( true, term );
- for( int i = 0; i < matches.size(); i++ ) {
- cout << matches[i] << endl;
- }
- if( matches.size() == 0 ) {
- return 1;
- }
- return 0;
-}
-
-int cat_note( note_list list, string name ) {
- vector<string> body;
- if( list.cat_note( name, &body ) == 0 ) {
- // If list returns true, the note exists
- for( int i = 0; i < body.size(); i++ ) {
- cout << body[i] << endl;
- }
- } else {
- // List cat_note returned false. Note doesn't exist
- cout << "Note " << name << " could not be found." << endl;
- return 1;
- }
- return 0;
-}
-
-int main( int argc, char** argv ) {
+// void list_notes( note_list list ) {
+// // List notes
+// vector<string> names = list.enum_names();
+// cout << endl;
+// for( int i = 0; i < names.size(); i++ ) {
+// cout << "* " << names[i] << endl;
+// }
+// cout << endl;
+// }
+//
+// /**
+// * Searches all note contents for the specified text
+// */
+// int search_notes( note_list list, string term ) {
+// vector<string> matches = list.find( true, term );
+// for( int i = 0; i < matches.size(); i++ ) {
+// cout << matches[i] << endl;
+// }
+// if( matches.size() == 0 ) {
+// return 1;
+// }
+// return 0;
+// }
+//
+// int cat_note( note_list list, string name ) {
+// vector<string> body;
+// if( list.cat_note( name, &body ) == 0 ) {
+// // If list returns true, the note exists
+// for( int i = 0; i < body.size(); i++ ) {
+// cout << body[i] << endl;
+// }
+// } else {
+// // List cat_note returned false. Note doesn't exist
+// cout << "Note " << name << " could not be found." << endl;
+// return 1;
+// }
+// return 0;
+// }
+
+int main(int argc, char* argv[]) {
/**
- * Config variables definitions
+ * Config variables
*/
- // Default path to the note store
- string note_path = getenv( "HOME" );
- note_path += "/Documents/Notes";
+ char home_path[strlen(getenv("HOME"))];
+ strcpy(home_path, getenv("HOME"));
- // Default note extension
- string note_ext = "mdown";
+ /* Default path to the note store */
+ char* note_path = NULL;
- // A little editor detection
- string editor;
- if( getenv( "EDITOR" ) ) {
- editor = getenv( "EDITOR" );
- } else {
- editor = "vi";
- }
+ /* Default note extension */
+ char* note_ext = "mdown";
+
+ /* A little editor detection */
+ char* editor = NULL;
/**
* Config file overrides
*/
- string conf_path = getenv( "HOME" );
- conf_path += "/.config/noteless.conf";
- path pconf( conf_path );
- config conf();
- if( pconf.exists() ) {
- config conf( conf_path.c_str() );
-
- // Override where notes are to be stored
- if( conf.isset( "path" ) ) {
- note_path = conf.get( "path" );
- }
-
- // Override the extension used by the notes
- if( conf.isset( "extension" ) ) {
- note_ext = conf.get( "extension" );
- }
-
- // Override editor settings
- if( conf.isset( "editor" ) ) {
- editor = conf.get( "editor" );
- }
- }
+ char conf_path[strlen(home_path) + 23];
+ strcpy(conf_path, home_path);
+ strcat(conf_path, "/.config/noteless.conf");
- if( argc == 1 ) {
- cout << "\nNo command specified. Printing help text.\n" << endl;
- return get_help();
- }
+ config_t c;
+ config_new(&c, conf_path);
+
+ // Override where notes are to be stored
+ // The local version of note path, in case it isn't set in the config
+ char tmp_note_path[strlen(home_path) + 17];
- // If the init command was passed, we want to init before checking if the
- // note path exists, otherwise the error will display and the store will
- // never be initialized.
- if( string( argv[1] ) == "init" ) {
- path p( note_path );
- return p.create();
+ if(config_isset(&c, "path") == 1) {
+ note_path = config_get(&c, "path");
+ } else {
+ strcpy(tmp_note_path, home_path);
+ strcat(tmp_note_path, "/Documents/Notes");
+ note_path = tmp_note_path;
}
- // Check to make sure the note path exists
- path p( note_path );
- if( ! p.exists() ) {
- string out =
- "\nThe note store path '" + p.out() + "' does not exist.\n\n"
- "If this is your first time running noteless, please run "
- "'noteless init' to\n"
- "create the note store here.\n\n"
- "Otherwise, please verify the path variable in your configuration.";
- cout << out << endl;
- return 1;
+ // Override the extension used by the notes
+ if(config_isset(&c, "extension")) {
+ note_ext = config_get(&c, "extension");
}
- // Create new list
- note_list list( note_path, note_ext );
-
- for( int i = 1; i < argc; i++ ) {
- string arg = argv[i];
- if( arg == "ls" || arg == "list" ) {
- list_notes( list );
- } else if( arg == "new" ) {
- string name = argv[i + 1];
- return list.create( editor, name );
- } else if( arg == "edit" ) {
- string name = argv[i + 1];
- return list.edit( editor, name );
- } else if( arg == "rm" ) {
- string name = argv[i + 1];
- return list.rm( name );
- } else if( arg == "find" ) {
- string term = argv[i + 1];
- return search_notes( list, term );
- } else if( arg == "cat" ) {
- string name = argv[i + 1];
- return cat_note( list, name );
- } else if( arg == "help" ) {
- return get_help();
- } else if( list.find_note_id( arg ) != -1 ) {
- // Try to open the note if it exists
- return list.edit( editor, arg );
- } else {
- cout << "Error: Unknown command or note name '" << arg << "'." << endl;
- return 1;
- }
+ // Override editor settings
+ char tmp_editor[128];
+ if(config_isset(&c, "editor")) {
+ editor = config_get(&c, "editor");
+ } else {
+ get_user_editor(tmp_editor);
+ editor = tmp_editor;
}
+
+
+ // Verbose variable outputs
+ printf("Note Path: %s\n", note_path);
+ printf("Note Ext: %s\n", note_ext);
+ printf("Conf Path: %s\n", conf_path);
+ printf("Editor: %s\n", editor);
+
+ config_free(&c);
+
+ // if( argc == 1 ) {
+ // cout << "\nNo command specified. Printing help text.\n" << endl;
+ // return get_help();
+ // }
+
+ // // If the init command was passed, we want to init before checking if the
+ // // note path exists, otherwise the error will display and the store will
+ // // never be initialized.
+ // if( string( argv[1] ) == "init" ) {
+ // path p( note_path );
+ // return p.create();
+ // }
+
+ // // Check to make sure the note path exists
+ // path p( note_path );
+ // if( ! p.exists() ) {
+ // string out =
+ // "\nThe note store path '" + p.out() + "' does not exist.\n\n"
+ // "If this is your first time running noteless, please run "
+ // "'noteless init' to\n"
+ // "create the note store here.\n\n"
+ // "Otherwise, please verify the path variable in your configuration.";
+ // cout << out << endl;
+ // return 1;
+ // }
+
+ // // Create new list
+ // note_list list( note_path, note_ext );
+
+ // for( int i = 1; i < argc; i++ ) {
+ // string arg = argv[i];
+ // if( arg == "ls" || arg == "list" ) {
+ // list_notes( list );
+ // } else if( arg == "new" ) {
+ // string name = argv[i + 1];
+ // return list.create( editor, name );
+ // } else if( arg == "edit" ) {
+ // string name = argv[i + 1];
+ // return list.edit( editor, name );
+ // } else if( arg == "rm" ) {
+ // string name = argv[i + 1];
+ // return list.rm( name );
+ // } else if( arg == "find" ) {
+ // string term = argv[i + 1];
+ // return search_notes( list, term );
+ // } else if( arg == "cat" ) {
+ // string name = argv[i + 1];
+ // return cat_note( list, name );
+ // } else if( arg == "help" ) {
+ // return get_help();
+ // } else if( list.find_note_id( arg ) != -1 ) {
+ // // Try to open the note if it exists
+ // return list.edit( editor, arg );
+ // } else {
+ // cout << "Error: Unknown command or note name '" << arg << "'." << endl;
+ // return 1;
+ // }
+ // }
return 0;
}

Generated by cgit