Initial commit. Added old code. Added README

This commit is contained in:
nedko 2022-12-07 17:32:08 +02:00
commit 0102605c07
10 changed files with 866 additions and 0 deletions

9
Makefile Normal file
View File

@ -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

110
MindNode.cpp Normal file
View File

@ -0,0 +1,110 @@
#include <iostream>
#include <exception>
#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<string>
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);
}

58
MindNode.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef MIND_NODE_H_
#define MIND_NODE_H_
#include <string>
#include <vector>
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<string> 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<string> 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_

19
README Normal file
View File

@ -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

3
command.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
cd "${BASH_SOURCE%/*}/"
./watcher ../src/ ../dst/ &

BIN
files.zip Normal file

Binary file not shown.

56
mindgen.cpp Normal file
View File

@ -0,0 +1,56 @@
#include <fstream>
#include <iostream>
#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<string> vec = root->getIcons();
for (vector<string>::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;
}

344
mindgen_funcs.cpp Normal file
View File

@ -0,0 +1,344 @@
#include <cctype>
#include <cstring>
#include <iostream>
#include <map>
#include <vector>
#include "mindgen_funcs.h"
using namespace std;
struct tag_struct
{
string name;
map<string, string> 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 << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
out << "<?xml-stylesheet href=\"files/treestyles.css\" type=\"text/css\"?>" << endl;
out << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">" << endl;
out << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
out << "\t<head>" << endl;
out << "\t\t<meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\" />" << endl;
out << "\t\t<title>";
break;
case 1:
out << "</title>" << endl;
out << "\t\t<link rel=\"stylesheet\" href=\"files/treestyles.css\" type=\"text/css\" />" << endl;
out << "\t\t<script type=\"text/javascript\" src=\"files/marktree.js\"></script>" << endl;
out << "\t</head>" << endl;
out << "\t<body>" << endl;
out << "\t\t<div class=\"basetop\">" << endl;
out << "\t\t\t<a onclick=\"expandAll(document.getElementById('base'))\" href=\"#\">Expand</a>" << endl;
out << "\t\t\t-" << endl;
out << "\t\t\t<a onclick=\"collapseAll(document.getElementById('base'))\" href=\"#\">Collapse</a>" << endl;
out << "\t\t</div>" << endl;
out << "\t\t<div class=\"basetext\" id=\"base\">" << endl;
out << "\t\t\t<ul>" << endl;
break;
case 2:
out << "\t\t\t</ul>" << endl;
out << "\t\t</div>" << endl;
out << "\t</body>" << endl;
out << "</html>" << 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 << "<li class=\"basic\" id=\"FM" << root->getID() << "FM\">" << endl;
}
else
{
out << "<li class=\"col\" id=\"FM" << root->getID() << "FM\">" << endl;
}
// If there are icons - print them
if (!root->getIcons().empty())
{
vector<string> icons = root->getIcons();
for (vector<string>::iterator it = icons.begin(); it != icons.end(); ++it)
{
indent(out, indent_count + 1);
out << "<img src=\"files/icons/" << *it << ".png\"/>" << endl;
}
}
indent(out, indent_count + 1);
out << "<div class=\"nodecontent\">" << endl;
indent(out, indent_count + 2);
if (!root->getLink().empty())
{
out << "<a href=\"" << root->getLink() << "\">";
}
out << root->getText();
if (!root->getLink().empty())
{
out << "</a>" << endl;
indent(out, indent_count + 2);
out << "<a href=\"" << root->getLink() << "\">" << endl;
indent(out, indent_count + 3);
out << "<img src=\"files/ilink.png\" style=\"border-width:0\" />" << endl;
indent(out, indent_count + 2);
out << "</a>";
}
out << endl;
indent(out, indent_count + 1);
out << "</div>" << endl;
if (NULL != root->getFirstChild())
{
indent(out, indent_count + 1);
out << "<ul class=\"subexp\">" << endl;
write_node_recursive(out, root->getFirstChild(), indent_count + 2);
indent(out, indent_count + 1);
out << "</ul>" << endl;
}
indent(out, indent_count);
out << "</li>" << 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<string, string>(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);
}

15
mindgen_funcs.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef MINDGEN_FUNCS_H_
#define MINDGEN_FUNCS_H_
#include <iostream>
#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_

252
watcher.c Normal file
View File

@ -0,0 +1,252 @@
#include <sys/types.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}