commit 0102605c076905b93e263aba12004cdab0f531b5 Author: nedko Date: Wed Dec 7 17:32:08 2022 +0200 Initial commit. Added old code. Added README diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..47c782c --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +all: + make mindgen + make watcher + +mindgen: + g++ MindNode.cpp mindgen_funcs.cpp mindgen.cpp -o mindgen + +watcher: + gcc watcher.c -o watcher diff --git a/MindNode.cpp b/MindNode.cpp new file mode 100644 index 0000000..0e644e2 --- /dev/null +++ b/MindNode.cpp @@ -0,0 +1,110 @@ +#include +#include + +#include "MindNode.h" + +using namespace std; + +MindNode::MindNode() +: m_parent(NULL), m_first_child(NULL), m_next_node(NULL), m_id(""), + m_text(""), m_link(""), m_icons() +{ +} + +MindNode::~MindNode() +{ + MindNode* curr_child; + MindNode* next_child; + + curr_child = m_first_child; + while (NULL != curr_child) + { + next_child = curr_child->m_next_node; + delete curr_child; + curr_child = next_child; + } +} + +MindNode* +MindNode::getParent() const +{ + return m_parent; +} + +MindNode* +MindNode::getFirstChild() const +{ + return m_first_child; +} + +MindNode* +MindNode::getNextNode() const +{ + return m_next_node; +} + +string +MindNode::getID() const +{ + return m_id; +} + +string +MindNode::getText() const +{ + return m_text; +} + +string +MindNode::getLink() const +{ + return m_link; +} + +vector +MindNode::getIcons() const +{ + return m_icons; +} + +void +MindNode::setParent(MindNode* parent) +{ + m_parent = parent; +} + +void +MindNode::setFirstChild(MindNode* first_child) +{ + m_first_child = first_child; +} + +void +MindNode::setNextNode(MindNode* next_node) +{ + m_next_node = next_node; +} + +void +MindNode::setID(string& id) +{ + m_id = id; +} + +void +MindNode::setText(string& text) +{ + m_text = text; +} + +void +MindNode::setLink(string& link) +{ + m_link = link; +} + +void +MindNode::addIcon(string& icon) +{ + m_icons.push_back(icon); +} diff --git a/MindNode.h b/MindNode.h new file mode 100644 index 0000000..1040cd4 --- /dev/null +++ b/MindNode.h @@ -0,0 +1,58 @@ +#ifndef MIND_NODE_H_ +#define MIND_NODE_H_ + +#include +#include + +using std::string; +using std::vector; + +class MindNode +{ +private: + // The parent of this node in the tree + MindNode* m_parent; + + // The first child of this node in the tree + MindNode* m_first_child; + + // The next node with the same parent in the tree + MindNode* m_next_node; + + // ID of the node + string m_id; + + // Content of the node + string m_text; + + // Link of the node + string m_link; + + // Array of all icons in this node + vector m_icons; + +public: + // Default Constructor & Destructor + MindNode(); + ~MindNode(); + + // Getters + MindNode* getParent() const; + MindNode* getFirstChild() const; + MindNode* getNextNode() const; + string getID() const; + string getText() const; + string getLink() const; + vector getIcons() const; + + // Setters + void setParent(MindNode* _parent); + void setFirstChild(MindNode* _first_child); + void setNextNode(MindNode* _next_node); + void setID(string& _id); + void setText(string& _text); + void setLink(string& _link); + void addIcon(string& _icon); +}; + +#endif // MIND_NODE_H_ diff --git a/README b/README new file mode 100644 index 0000000..6bf2943 --- /dev/null +++ b/README @@ -0,0 +1,19 @@ +# How to use +### Preparation +You will need 2 folders + +1. In the "source" folder you will add/modify/remove FreeMind .mm files +Please do not use it for anything else. + +2. In the "destination" folder will be automatically generated/delete html files. +If the source file is named "map.mm" then the resulting html file will be "map.mm.html". +The "files.zip" must be unpacked in the "destination" folder such that there is a single level "files" folder. + +### Usage +Invoke the "watcher" executable from a directory where the "mindgen" is located (usually the same one) +``` +./watcher /path/to/src /path/to/dst +``` + +### command.sh +Example script that automatically changes the working directory to its location and executes the watcher diff --git a/command.sh b/command.sh new file mode 100755 index 0000000..e847c1b --- /dev/null +++ b/command.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd "${BASH_SOURCE%/*}/" +./watcher ../src/ ../dst/ & diff --git a/files.zip b/files.zip new file mode 100644 index 0000000..a1d76d7 Binary files /dev/null and b/files.zip differ diff --git a/mindgen.cpp b/mindgen.cpp new file mode 100644 index 0000000..6713864 --- /dev/null +++ b/mindgen.cpp @@ -0,0 +1,56 @@ +#include +#include + +#include "mindgen_funcs.h" +#include "MindNode.h" + +using namespace std; + +void printTree(MindNode* root) +{/* + if (root != NULL) + { + cout << "ID: " << root->getID() << endl; + cout << "TEXT: " << root->getText() << endl; + cout << "LINK: " << root->getLink() << endl; + vector vec = root->getIcons(); + for (vector::iterator it = vec.begin(); it != vec.end(); ++it) + { + cout << "ICON: " << *it << endl; + } + + cout << "DOWN" << endl; + printTree(root->getFirstChild()); + + cout << "RIGHT" << endl; + printTree(root->getNextNode()); + } + cout << "UP" << endl;*/ +} + +int main(int argc, char** argv) +{ + ifstream input_file; + ofstream output_file; + MindNode* root; + + if (argc < 3) + { + cout << "Usage: " << argv[0] << " [mindmap] [output]" << endl; + return -1; + } + input_file.open(argv[1]); + output_file.open(argv[2]); + + if (0 != parse_mindmap(input_file, &root)) + { + cout << "ERR" << endl; + return -1; + } + + printTree(root); + + write_html(output_file, root); + delete root; + return 0; +} diff --git a/mindgen_funcs.cpp b/mindgen_funcs.cpp new file mode 100644 index 0000000..fc637a5 --- /dev/null +++ b/mindgen_funcs.cpp @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include + +#include "mindgen_funcs.h" + +using namespace std; + +struct tag_struct +{ + string name; + map params; + bool is_closed; + bool is_closing; +}; + +void indent(ostream& _out, int _count); +void write_initial_html(ostream& _out, int _part); +void write_node_recursive(ostream& _out, const MindNode* _root, int _indent_count); +void get_tag(istream& _in, string& _content); +void generate_map(string& _content, tag_struct& _tag); + +// DEFININTIONS +void +indent(ostream& out, int count) +{ + for (int i = 0; i < count; ++i) + { + out << "\t"; + } +} + +void +write_initial_html(ostream& out, int part) +{ + switch (part) + { + case 0: + out << "" << endl; + out << "" << endl; + out << "" << endl; + out << "" << endl; + out << "\t" << endl; + out << "\t\t" << endl; + out << "\t\t"; + break; + + case 1: + out << "" << endl; + out << "\t\t" << endl; + out << "\t\t" << endl; + out << "\t" << endl; + out << "\t" << endl; + out << "\t\t
" << endl; + out << "\t\t\tExpand" << endl; + out << "\t\t\t-" << endl; + out << "\t\t\tCollapse" << endl; + out << "\t\t
" << endl; + out << "\t\t
" << endl; + out << "\t\t\t
    " << endl; + break; + + case 2: + out << "\t\t\t
" << endl; + out << "\t\t
" << endl; + out << "\t" << endl; + out << "" << endl; + break; + } +} + +void +write_node_recursive(ostream& out, const MindNode* root, int indent_count) +{ + while (NULL != root) + { + indent(out, indent_count); + if (NULL == root->getFirstChild()) + { + out << "
  • getID() << "FM\">" << endl; + } + else + { + out << "
  • getID() << "FM\">" << endl; + } + + // If there are icons - print them + if (!root->getIcons().empty()) + { + vector icons = root->getIcons(); + for (vector::iterator it = icons.begin(); it != icons.end(); ++it) + { + indent(out, indent_count + 1); + out << "" << endl; + } + } + + indent(out, indent_count + 1); + out << "
    " << endl; + + indent(out, indent_count + 2); + if (!root->getLink().empty()) + { + out << "getLink() << "\">"; + } + + out << root->getText(); + + if (!root->getLink().empty()) + { + out << "" << endl; + indent(out, indent_count + 2); + out << "getLink() << "\">" << endl; + + indent(out, indent_count + 3); + out << "" << endl; + + indent(out, indent_count + 2); + out << ""; + } + + out << endl; + + indent(out, indent_count + 1); + out << "
    " << endl; + + if (NULL != root->getFirstChild()) + { + indent(out, indent_count + 1); + out << "
      " << endl; + write_node_recursive(out, root->getFirstChild(), indent_count + 2); + + indent(out, indent_count + 1); + out << "
    " << endl; + } + indent(out, indent_count); + out << "
  • " << endl; + + root = root->getNextNode(); + } +} + +void +get_tag(istream& in, string& content) +{ + char symbol; + + in.get(symbol); + while ('>' != symbol) + { + content += symbol; + in.get(symbol); + } +} + +void +generate_map(string& content, tag_struct& tag) +{ + size_t index; + string name; + string value; + + tag.params.clear(); + tag.name.clear(); + tag.is_closed = false; + tag.is_closing = false; + + // Removes header / trailer slashes and skips comments + if ('/' == content[0]) + { + tag.is_closing = true; + content.erase(0, 1); + } + if ('/' == content[content.size() - 1]) + { + tag.is_closed = true; + content.erase(content.size() - 1, 1); + } + if ('!' == content[0]) + { + return; + } + + // First word is the name + index = content.find(' '); + tag.name = content.substr(0, index); + if (string::npos == index) + { + content.clear(); + } + else + { + content.erase(0, index + 1); + } + // If we have more than just a name + while (!content.empty()) + { + index = content.find('='); + name = content.substr(0, index); + content.erase(0, index + 2); + + index = content.find('"'); + value = content.substr(0, index); + content.erase(0, index + 1); + tag.params.insert(pair(name, value)); + if (!content.empty()) + { + content.erase(0, 1); + } + } +} + +// HEADER FUNCS + +int +parse_mindmap(istream& in, MindNode** root) +{ + char parse = '\0'; + string search; + string content; + tag_struct current_tag; + + MindNode* current_node = NULL; + + while (!in.eof()) + { + // Find Next Tag + in.get(parse); + while ((parse != '<') && (!in.eof())) + { + in.get(parse); + } + if (in.eof()) + { + break; + } + + content = ""; + get_tag(in, content); + generate_map(content, current_tag); + + // Map parse + + if ("map" == current_tag.name) + { + if (NULL != current_node) + { + return -1; + } + } + + // Node Parse + if ("node" == current_tag.name) + { + if (current_tag.is_closing) + { + current_node = current_node->getParent(); + } + else + { + MindNode* node_new = new MindNode(); + + node_new->setID(current_tag.params.find("ID")->second); + + if (current_tag.params.end() != current_tag.params.find("TEXT")) + { + node_new->setText(current_tag.params.find("TEXT")->second); + } + + if (current_tag.params.end() != current_tag.params.find("LINK")) + { + node_new->setLink(current_tag.params.find("LINK")->second); + } + + if (NULL == current_node) + { + *root = node_new; + } + else + { + node_new->setParent(current_node); + + if(NULL == current_node->getFirstChild()) + { + current_node->setFirstChild(node_new); + } + else + { + MindNode* last_child = current_node->getFirstChild(); + while(NULL != last_child->getNextNode()) + { + last_child = last_child->getNextNode(); + } + last_child->setNextNode(node_new); + } + } + current_node = node_new; + + if (current_tag.is_closed) + { + current_node = current_node->getParent(); + } + } + } + + if ("icon" == current_tag.name) + { + if (current_tag.params.end() != current_tag.params.find("BUILTIN")) + { + current_node->addIcon(current_tag.params.find("BUILTIN")->second); + } + } + } + cout << endl; + return 0; +} + +void +write_html(ostream& out, const MindNode* root) +{ + if (NULL == root) + { + cerr << "Error at \"" << __FILE__ << "\" on line " << __LINE__ << endl; + cerr << "Root node is NULL" << endl; + return; + } + + // Write first part html + write_initial_html(out, 0); + + // Write title + out << root->getText(); + + // Write next part html + write_initial_html(out, 1); + + // Write node structure + write_node_recursive(out, root, 4); + + // Write last part html + write_initial_html(out, 2); +} diff --git a/mindgen_funcs.h b/mindgen_funcs.h new file mode 100644 index 0000000..01839c6 --- /dev/null +++ b/mindgen_funcs.h @@ -0,0 +1,15 @@ +#ifndef MINDGEN_FUNCS_H_ +#define MINDGEN_FUNCS_H_ + +#include + +#include "MindNode.h" + +using std::istream; +using std::ostream; + +int parse_mindmap(istream& in, MindNode** root); + +void write_html(ostream& out, const MindNode* root); + +#endif // MINDGEN_FUNCS_H_ diff --git a/watcher.c b/watcher.c new file mode 100644 index 0000000..0e93a83 --- /dev/null +++ b/watcher.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define POLL_TIME_SEC 60 + +/* + * Prints the usage string + */ +void usage(const char* _name); + +/* + * Checks if the filepath is a directory or not + * + * Returns -1 on error; 0 on false; 1 on true + */ +int is_dir(const char* _filepath); + +/* + * Executes the generation command + * + * Returns -1 on error; + */ +int execute_mindgen(); + +/* + * Executes the deletion command + * + * Returns -1 on error; + */ +int execute_delete(const char* _dir, const char* _filename); + +int main(int argc, char** argv) +{ + int notify_fd; + int watch_fd; + int error; + bool deleted; + unsigned int buffer_size; + char* buffer; + int offset; + + // [name] [watch dir] [destination dir] + if (argc < 3) + { + usage(argv[0]); + return 1; + } + + // Check dirs and permissions + if (1 != is_dir(argv[1])) + { + usage(argv[0]); + printf("Watch directory is not a folder, does not exist or there are not sufficient permissions.\n"); + } + + if (1 != is_dir(argv[2])) + { + usage(argv[0]); + printf("Destination directory is not a folder, does not exist or there are not sufficient permissions.\n"); + } + + // inotify init + notify_fd = inotify_init(); + if (notify_fd < 0) + { + printf("BAD NOTIFY FD\n"); + return -1; + } + + // inotify add watch + watch_fd = inotify_add_watch(notify_fd, argv[1], IN_DELETE | IN_DELETE_SELF | IN_CLOSE_WRITE); + if (watch_fd < 0) + { + printf("BAD WATCH FD\n"); + close(notify_fd); + return -1; + } + + deleted = false; + while (!deleted) + { + // wait for event + buffer_size = 0; + while (0 == buffer_size) + { + sleep(POLL_TIME_SEC); + error = ioctl(notify_fd, FIONREAD, &buffer_size); + if (0 != error) + { + printf("BAD IOCTL\n"); + return -1; + } + } + + // Create big enough buffer and read all data + buffer = (char*)malloc(buffer_size); + error = read(notify_fd, buffer, buffer_size); + if (error != buffer_size) + { + printf("BAD BUFFER SIZE\n"); + free(buffer); + close(notify_fd); + return -1; + } + + // Read and process all events + offset = 0; + while (offset < buffer_size) + { + struct inotify_event* event = (struct inotify_event*)(buffer + offset); + + // on create/modify - mindgen + if (0 != (event->mask & IN_CLOSE_WRITE)) + { + //printf("FILE WRITTEN TO: %s\n", event->name); + execute_mindgen(argv[2], event->name, argv[1]); + } + + // on delete - rm + if (0 != (event->mask & IN_DELETE)) + { + //printf("DELETE: %s\n", event->name); + execute_delete(argv[2], event->name); + } + + // on delete_self - exit + if (0 != (event->mask & IN_DELETE_SELF)) + { + printf("Watched folder deleted. Stopping.\n"); + deleted = true; + } + offset += sizeof(struct inotify_event) + event->len; + } + free(buffer); + buffer = NULL; + } + + return 0; +} + +void +usage(const char* name) +{ + if (NULL == name) + { + return; + } + + printf("%s watch_dir dest_dir\n", name); +} + +int +is_dir(const char* filepath) +{ + int result; + struct stat file_stat; + + if (NULL == filepath) + { + return -1; + } + result = stat(filepath, &file_stat); + if (0 == result) + { + if (S_ISDIR(file_stat.st_mode)) + { + result = 1; + } + } + return result; +} + +int execute_mindgen(const char* dest_dir, const char* filename, const char* source_dir) +{ + int pid; + int child_status; + char source_fullname[strlen(source_dir) + strlen(filename) + 2]; + char dest_fullname[strlen(source_dir) + strlen(filename) + 7]; + char* arglist[4]; + + pid = fork(); + if (pid < 0) + { + printf("Error trying to generate html.\n"); + return -1; + } + if (0 == pid) + { + strcpy(source_fullname, source_dir); + strcat(source_fullname, "/"); + strcat(source_fullname, filename); + + strcpy(dest_fullname, dest_dir); + strcat(dest_fullname, "/"); + strcat(dest_fullname, filename); + strcat(dest_fullname, ".html"); + + arglist[0] = "mindgen"; + arglist[1] = source_fullname; + arglist[2] = dest_fullname; + arglist[3] = NULL; + //printf("%s %s %s\n", arglist[0], arglist[1], arglist[2]); + execv("./mindgen", arglist); + + printf("Error generating html.\n"); + return -1; + } + wait(&child_status); + return 0; +} + +int execute_delete(const char* dir, const char* filename) +{ + int pid; + int child_status; + char fullname[strlen(dir) + strlen(filename) + 7]; + char* arglist[3]; + + pid = fork(); + if (pid < 0) + { + printf("Error trying to delete.\n"); + return -1; + } + if (0 == pid) + { + strcpy(fullname, dir); + strcat(fullname, "/"); + strcat(fullname, filename); + strcat(fullname, ".html"); + + arglist[0] = "rm"; + arglist[1] = fullname; + arglist[2] = NULL; + //printf("%s %s\n", arglist[0], arglist[1]); + execv("/bin/rm", arglist); + + printf("Error deleting.\n"); + return -1; + } + wait(&child_status); + return 0; +}