diff options
Diffstat (limited to '')
-rw-r--r-- | ml/dlib/tools/htmlify/CMakeLists.txt | 31 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/htmlify.cpp | 632 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml.cpp | 1599 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml.h | 22 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/bigminus.gif | bin | 0 -> 91 bytes | |||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/bigplus.gif | bin | 0 -> 99 bytes | |||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/example.xml | 8 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/minus.gif | bin | 0 -> 56 bytes | |||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/output.xml | 49 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/plus.gif | bin | 0 -> 59 bytes | |||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/stylesheet.xsl | 354 | ||||
-rw-r--r-- | ml/dlib/tools/htmlify/to_xml_example/test.cpp | 78 |
12 files changed, 2773 insertions, 0 deletions
diff --git a/ml/dlib/tools/htmlify/CMakeLists.txt b/ml/dlib/tools/htmlify/CMakeLists.txt new file mode 100644 index 000000000..02cae2172 --- /dev/null +++ b/ml/dlib/tools/htmlify/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# + +cmake_minimum_required(VERSION 2.8.12) + +# create a variable called target_name and set it to the string "htmlify" +set (target_name htmlify) + +project(${target_name}) + +add_subdirectory(../../dlib dlib_build) + +# add all the cpp files we want to compile to this list. This tells +# cmake that they are part of our target (which is the executable named htmlify) +add_executable(${target_name} + htmlify.cpp + to_xml.cpp + ) + +# Tell cmake to link our target executable to dlib. +target_link_libraries(${target_name} dlib::dlib ) + + + +install(TARGETS ${target_name} + RUNTIME DESTINATION bin + ) + + diff --git a/ml/dlib/tools/htmlify/htmlify.cpp b/ml/dlib/tools/htmlify/htmlify.cpp new file mode 100644 index 000000000..e822a5aaa --- /dev/null +++ b/ml/dlib/tools/htmlify/htmlify.cpp @@ -0,0 +1,632 @@ +#include <fstream> +#include <iostream> +#include <string> + + +#include "dlib/cpp_pretty_printer.h" +#include "dlib/cmd_line_parser.h" +#include "dlib/queue.h" +#include "dlib/misc_api.h" +#include "dlib/dir_nav.h" +#include "to_xml.h" + + +const char* VERSION = "3.5"; + +using namespace std; +using namespace dlib; + +typedef cpp_pretty_printer::kernel_1a cprinter; +typedef cpp_pretty_printer::kernel_2a bprinter; +typedef dlib::map<string,string>::kernel_1a map_string_to_string; +typedef dlib::set<string>::kernel_1a set_of_string; +typedef queue<file>::kernel_1a queue_of_files; +typedef queue<directory>::kernel_1a queue_of_dirs; + +void print_manual ( +); +/*! + ensures + - prints detailed information about this program. +!*/ + +void htmlify ( + const map_string_to_string& file_map, + bool colored, + bool number_lines, + const std::string& title +); +/*! + ensures + - for all valid out_file: + - the file out_file is the html transformed version of + file_map[out_file] + - if (number_lines) then + - the html version will have numbered lines + - if (colored) then + - the html version will have colors + - title will be the first part of the HTML title in the output file +!*/ + +void htmlify ( + istream& in, + ostream& out, + const std::string& title, + bool colored, + bool number_lines +); +/*! + ensures + - transforms in into html with the given title and writes it to out. + - if (number_lines) then + - the html version of in will have numbered lines + - if (colored) then + - the html version of in will have colors +!*/ + +void add_files ( + const directory& dir, + const std::string& out_dir, + map_string_to_string& file_map, + bool flatten, + bool cat, + const set_of_string& filter, + unsigned long search_depth, + unsigned long cur_depth = 0 +); +/*! + ensures + - searches the directory dir for files matching the filter and adds them + to the file_map. only looks search_depth deep. +!*/ + +int main(int argc, char** argv) +{ + if (argc == 1) + { + cout << "\nTry the -h option for more information.\n"; + return 0; + } + + string file; + try + { + command_line_parser parser; + parser.add_option("b","Pretty print in black and white. The default is to pretty print in color."); + parser.add_option("n","Number lines."); + parser.add_option("h","Displays this information."); + parser.add_option("index","Create an index."); + parser.add_option("v","Display version."); + parser.add_option("man","Display the manual."); + parser.add_option("f","Specifies a list of file extensions to process when using the -i option. The list elements should be separated by spaces. The default is \"cpp h c\".",1); + parser.add_option("i","Specifies an input directory.",1); + parser.add_option("cat","Puts all the output into a single html file with the given name.",1); + parser.add_option("depth","Specifies how many directories deep to search when using the i option. The default value is 30.",1); + parser.add_option("o","This option causes all the output files to be created inside the given directory. If this option is not given then all output goes to the current working directory.",1); + parser.add_option("flatten","When this option is given it prevents the input directory structure from being replicated."); + parser.add_option("title","This option specifies a string which is prepended onto the title of the generated HTML",1); + parser.add_option("to-xml","Instead of generating HTML output, create a single output file called output.xml that contains " + "a simple XML database which lists all documented classes and functions."); + parser.add_option("t", "When creating XML output, replace tabs in comments with <arg> spaces.", 1); + + + parser.parse(argc,argv); + + + parser.check_incompatible_options("cat","o"); + parser.check_incompatible_options("cat","flatten"); + parser.check_incompatible_options("cat","index"); + parser.check_option_arg_type<unsigned long>("depth"); + parser.check_option_arg_range("t", 1, 100); + + parser.check_incompatible_options("to-xml", "b"); + parser.check_incompatible_options("to-xml", "n"); + parser.check_incompatible_options("to-xml", "index"); + parser.check_incompatible_options("to-xml", "cat"); + parser.check_incompatible_options("to-xml", "o"); + parser.check_incompatible_options("to-xml", "flatten"); + parser.check_incompatible_options("to-xml", "title"); + + const char* singles[] = {"b","n","h","index","v","man","f","cat","depth","o","flatten","title","to-xml", "t"}; + parser.check_one_time_options(singles); + + const char* i_sub_ops[] = {"f","depth","flatten"}; + parser.check_sub_options("i",i_sub_ops); + + const char* to_xml_sub_ops[] = {"t"}; + parser.check_sub_options("to-xml",to_xml_sub_ops); + + const command_line_parser::option_type& b_opt = parser.option("b"); + const command_line_parser::option_type& n_opt = parser.option("n"); + const command_line_parser::option_type& h_opt = parser.option("h"); + const command_line_parser::option_type& index_opt = parser.option("index"); + const command_line_parser::option_type& v_opt = parser.option("v"); + const command_line_parser::option_type& o_opt = parser.option("o"); + const command_line_parser::option_type& man_opt = parser.option("man"); + const command_line_parser::option_type& f_opt = parser.option("f"); + const command_line_parser::option_type& cat_opt = parser.option("cat"); + const command_line_parser::option_type& i_opt = parser.option("i"); + const command_line_parser::option_type& flatten_opt = parser.option("flatten"); + const command_line_parser::option_type& depth_opt = parser.option("depth"); + const command_line_parser::option_type& title_opt = parser.option("title"); + const command_line_parser::option_type& to_xml_opt = parser.option("to-xml"); + + + string filter = "cpp h c"; + + bool cat = false; + bool color = true; + bool number = false; + unsigned long search_depth = 30; + + string out_dir; // the name of the output directory if the o option is given. "" otherwise + string full_out_dir; // the full name of the output directory if the o option is given. "" otherwise + const char separator = directory::get_separator(); + + bool no_run = false; + if (v_opt) + { + cout << "Htmlify v" << VERSION + << "\nCompiled: " << __TIME__ << " " << __DATE__ + << "\nWritten by Davis King\n"; + cout << "Check for updates at http://dlib.net\n\n"; + no_run = true; + } + + if (h_opt) + { + cout << "This program pretty prints C or C++ source code to HTML.\n"; + cout << "Usage: htmlify [options] [file]...\n"; + parser.print_options(); + cout << "\n\n"; + no_run = true; + } + + if (man_opt) + { + print_manual(); + no_run = true; + } + + if (no_run) + return 0; + + if (f_opt) + { + filter = f_opt.argument(); + } + + if (cat_opt) + { + cat = true; + } + + if (depth_opt) + { + search_depth = string_cast<unsigned long>(depth_opt.argument()); + } + + if (to_xml_opt) + { + unsigned long expand_tabs = 0; + if (parser.option("t")) + expand_tabs = string_cast<unsigned long>(parser.option("t").argument()); + + generate_xml_markup(parser, filter, search_depth, expand_tabs); + return 0; + } + + if (o_opt) + { + // make sure this directory exists + out_dir = o_opt.argument(); + create_directory(out_dir); + directory dir(out_dir); + full_out_dir = dir.full_name(); + + // make sure the last character of out_dir is a separator + if (out_dir[out_dir.size()-1] != separator) + out_dir += separator; + if (full_out_dir[out_dir.size()-1] != separator) + full_out_dir += separator; + } + + if (b_opt) + color = false; + if (n_opt) + number = true; + + // this is a map of output file names to input file names. + map_string_to_string file_map; + + + // add all the files that are just given on the command line to the + // file_map. + for (unsigned long i = 0; i < parser.number_of_arguments(); ++i) + { + string in_file, out_file; + in_file = parser[i]; + string::size_type pos = in_file.find_last_of(separator); + if (pos != string::npos) + { + out_file = out_dir + in_file.substr(pos+1) + ".html"; + } + else + { + out_file = out_dir + in_file + ".html"; + } + + if (file_map.is_in_domain(out_file)) + { + if (file_map[out_file] != in_file) + { + // there is a file name colision in the output folder. definitly a bad thing + cout << "Error: Two of the input files have the same name and would overwrite each\n"; + cout << "other. They are " << in_file << " and " << file_map[out_file] << ".\n" << endl; + return 1; + } + else + { + continue; + } + } + + file_map.add(out_file,in_file); + } + + // pick out the filter strings + set_of_string sfilter; + istringstream sin(filter); + string temp; + sin >> temp; + while (sin) + { + if (sfilter.is_member(temp) == false) + sfilter.add(temp); + sin >> temp; + } + + // now get all the files given by the i options + for (unsigned long i = 0; i < i_opt.count(); ++i) + { + directory dir(i_opt.argument(0,i)); + add_files(dir, out_dir, file_map, flatten_opt, cat, sfilter, search_depth); + } + + if (cat) + { + file_map.reset(); + ofstream fout(cat_opt.argument().c_str()); + if (!fout) + { + throw error("Error: unable to open file " + cat_opt.argument()); + } + fout << "<html><title>" << cat_opt.argument() << "</title></html>"; + + const char separator = directory::get_separator(); + string file; + while (file_map.move_next()) + { + ifstream fin(file_map.element().value().c_str()); + if (!fin) + { + throw error("Error: unable to open file " + file_map.element().value()); + } + + string::size_type pos = file_map.element().value().find_last_of(separator); + if (pos != string::npos) + file = file_map.element().value().substr(pos+1); + else + file = file_map.element().value(); + + std::string title; + if (title_opt) + title = title_opt.argument(); + htmlify(fin, fout, title + file, color, number); + } + + } + else + { + std::string title; + if (title_opt) + title = title_opt.argument(); + htmlify(file_map,color,number,title); + } + + + + if (index_opt) + { + ofstream index((out_dir + "index.html").c_str()); + ofstream menu((out_dir + "menu.html").c_str()); + + if (!index) + { + cout << "Error: unable to create " << out_dir << "index.html\n\n"; + return 0; + } + + if (!menu) + { + cout << "Error: unable to create " << out_dir << "menu.html\n\n"; + return 0; + } + + + index << "<html><frameset cols='200,*'>"; + index << "<frame src='menu.html' name='menu'>"; + index << "<frame name='main'></frameset></html>"; + + menu << "<html><body><br>"; + + file_map.reset(); + while (file_map.move_next()) + { + if (o_opt) + { + file = file_map.element().key(); + if (file.find(full_out_dir) != string::npos) + file = file.substr(full_out_dir.size()); + else + file = file.substr(out_dir.size()); + } + else + { + file = file_map.element().key(); + } + // strip the .html from file + file = file.substr(0,file.size()-5); + menu << "<a href='" << file << ".html' target='main'>" + << file << "</a><br>"; + } + + menu << "</body></html>"; + + } + + } + catch (ios_base::failure&) + { + cout << "ERROR: unable to write to " << file << endl; + cout << endl; + } + catch (exception& e) + { + cout << e.what() << endl; + cout << "\nTry the -h option for more information.\n"; + cout << endl; + } +} + +// ------------------------------------------------------------------------------------------------- + +void htmlify ( + istream& in, + ostream& out, + const std::string& title, + bool colored, + bool number_lines +) +{ + if (colored) + { + static cprinter cp; + if (number_lines) + { + cp.print_and_number(in,out,title); + } + else + { + cp.print(in,out,title); + } + } + else + { + static bprinter bp; + if (number_lines) + { + bp.print_and_number(in,out,title); + } + else + { + bp.print(in,out,title); + } + } +} + +// ------------------------------------------------------------------------------------------------- + +void htmlify ( + const map_string_to_string& file_map, + bool colored, + bool number_lines, + const std::string& title +) +{ + file_map.reset(); + const char separator = directory::get_separator(); + string file; + while (file_map.move_next()) + { + ifstream fin(file_map.element().value().c_str()); + if (!fin) + { + throw error("Error: unable to open file " + file_map.element().value() ); + } + + ofstream fout(file_map.element().key().c_str()); + + if (!fout) + { + throw error("Error: unable to open file " + file_map.element().key()); + } + + string::size_type pos = file_map.element().value().find_last_of(separator); + if (pos != string::npos) + file = file_map.element().value().substr(pos+1); + else + file = file_map.element().value(); + + htmlify(fin, fout,title + file, colored, number_lines); + } +} + +// ------------------------------------------------------------------------------------------------- + +void add_files ( + const directory& dir, + const std::string& out_dir, + map_string_to_string& file_map, + bool flatten, + bool cat, + const set_of_string& filter, + unsigned long search_depth, + unsigned long cur_depth +) +{ + const char separator = directory::get_separator(); + + queue_of_files files; + queue_of_dirs dirs; + + dir.get_files(files); + + // look though all the files in the current directory and add the + // ones that match the filter to file_map + string name, ext, in_file, out_file; + files.reset(); + while (files.move_next()) + { + name = files.element().name(); + string::size_type pos = name.find_last_of('.'); + if (pos != string::npos && filter.is_member(name.substr(pos+1))) + { + in_file = files.element().full_name(); + + if (flatten) + { + pos = in_file.find_last_of(separator); + } + else + { + // figure out how much of the file's path we need to keep + // for the output file name + pos = in_file.size(); + for (unsigned long i = 0; i <= cur_depth && pos != string::npos; ++i) + { + pos = in_file.find_last_of(separator,pos-1); + } + } + + if (pos != string::npos) + { + out_file = out_dir + in_file.substr(pos+1) + ".html"; + } + else + { + out_file = out_dir + in_file + ".html"; + } + + if (file_map.is_in_domain(out_file)) + { + if (file_map[out_file] != in_file) + { + // there is a file name colision in the output folder. definitly a bad thing + ostringstream sout; + sout << "Error: Two of the input files have the same name and would overwrite each\n"; + sout << "other. They are " << in_file << " and " << file_map[out_file] << "."; + throw error(sout.str()); + } + else + { + continue; + } + } + + file_map.add(out_file,in_file); + + } + } // while (files.move_next()) + files.clear(); + + if (search_depth > cur_depth) + { + // search all the sub directories + dir.get_dirs(dirs); + dirs.reset(); + while (dirs.move_next()) + { + if (!flatten && !cat) + { + string d = dirs.element().full_name(); + + // figure out how much of the directorie's path we need to keep. + string::size_type pos = d.size(); + for (unsigned long i = 0; i <= cur_depth && pos != string::npos; ++i) + { + pos = d.find_last_of(separator,pos-1); + } + + // make sure this directory exists in the output directory tree + d = d.substr(pos+1); + create_directory(out_dir + separator + d); + } + + add_files(dirs.element(), out_dir, file_map, flatten, cat, filter, search_depth, cur_depth+1); + } + } + +} + +// ------------------------------------------------------------------------------------------------- + +void print_manual ( +) +{ + ostringstream sout; + + const unsigned long indent = 2; + + cout << "\n"; + sout << "Htmlify v" << VERSION; + cout << wrap_string(sout.str(),indent,indent); sout.str(""); + + + sout << "This is a fairly simple program that takes source files and pretty prints them " + << "in HTML. There are two pretty printing styles, black and white or color. The " + << "black and white style is meant to look nice when printed out on paper. It looks " + << "a little funny on the screen but on paper it is pretty nice. The color version " + << "on the other hand has nonprintable HTML elements such as links and anchors."; + cout << "\n\n" << wrap_string(sout.str(),indent,indent); sout.str(""); + + + sout << "The colored style puts HTML anchors on class and function names. This means " + << "you can link directly to the part of the code that contains these names. For example, " + << "if you had a source file bar.cpp with a function called foo in it you could link " + << "directly to the function with a link address of \"bar.cpp.html#foo\". It is also " + << "possible to instruct Htmlify to place HTML anchors at arbitrary spots by using a " + << "special comment of the form /*!A anchor_name */. You can put other things in the " + << "comment but the important bit is to have it begin with /*!A then some white space " + << "then the anchor name you want then more white space and then you can add whatever " + << "you like. You would then refer to this anchor with a link address of " + << "\"file.html#anchor_name\"."; + cout << "\n\n" << wrap_string(sout.str(),indent,indent); sout.str(""); + + sout << "Htmlify also has the ability to create a simple index of all the files it is given. " + << "The --index option creates a file named index.html with a frame on the left side " + << "that contains links to all the files."; + cout << "\n\n" << wrap_string(sout.str(),indent,indent); sout.str(""); + + + sout << "Finally, Htmlify can produce annotated XML output instead of HTML. The output will " + << "contain all functions which are immediately followed by comments of the form /*! comment body !*/. " + << "Similarly, all classes or structs that immediately contain one of these comments following their " + << "opening { will also be output as annotated XML. Note also that if you wish to document a " + << "piece of code using one of these comments but don't want it to appear in the output XML then " + << "use either a comment like /* */ or /*!P !*/ to mark the code as \"private\"."; + cout << "\n\n" << wrap_string(sout.str(),indent,indent) << "\n\n"; sout.str(""); +} + +// ------------------------------------------------------------------------------------------------- + diff --git a/ml/dlib/tools/htmlify/to_xml.cpp b/ml/dlib/tools/htmlify/to_xml.cpp new file mode 100644 index 000000000..7fae43380 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml.cpp @@ -0,0 +1,1599 @@ + +#include "to_xml.h" +#include "dlib/dir_nav.h" +#include <vector> +#include <sstream> +#include <iostream> +#include <fstream> +#include <stack> +#include "dlib/cpp_tokenizer.h" +#include "dlib/string.h" + +using namespace dlib; +using namespace std; + +// ---------------------------------------------------------------------------------------- + +typedef cpp_tokenizer::kernel_1a_c tok_type; + +// ---------------------------------------------------------------------------------------- + +class file_filter +{ +public: + + file_filter( + const string& filter + ) + { + // pick out the filter strings + istringstream sin(filter); + string temp; + sin >> temp; + while (sin) + { + endings.push_back("." + temp); + sin >> temp; + } + } + + bool operator() ( const file& f) const + { + // check if any of the endings match + for (unsigned long i = 0; i < endings.size(); ++i) + { + // if the ending is bigger than f's name then it obviously doesn't match + if (endings[i].size() > f.name().size()) + continue; + + // now check if the actual characters that make up the end of the file name + // matches what is in endings[i]. + if ( std::equal(endings[i].begin(), endings[i].end(), f.name().end()-endings[i].size())) + return true; + } + + return false; + } + + std::vector<string> endings; +}; + +// ---------------------------------------------------------------------------------------- + +void obtain_list_of_files ( + const cmd_line_parser<char>::check_1a_c& parser, + const std::string& filter, + const unsigned long search_depth, + std::vector<std::pair<string,string> >& files +) +{ + for (unsigned long i = 0; i < parser.option("i").count(); ++i) + { + const directory dir(parser.option("i").argument(0,i)); + + const std::vector<file>& temp = get_files_in_directory_tree(dir, file_filter(filter), search_depth); + + // figure out how many characters need to be removed from the path of each file + const string parent = dir.get_parent().full_name(); + unsigned long strip = parent.size(); + if (parent.size() > 0 && parent[parent.size()-1] != '\\' && parent[parent.size()-1] != '/') + strip += 1; + + for (unsigned long i = 0; i < temp.size(); ++i) + { + files.push_back(make_pair(temp[i].full_name().substr(strip), temp[i].full_name())); + } + } + + for (unsigned long i = 0; i < parser.number_of_arguments(); ++i) + { + files.push_back(make_pair(parser[i], parser[i])); + } + + std::sort(files.begin(), files.end()); +} + +// ---------------------------------------------------------------------------------------- + +struct tok_function_record +{ + std::vector<std::pair<int,string> > declaration; + string scope; + string file; + string comment; +}; + +struct tok_method_record +{ + std::vector<std::pair<int,string> > declaration; + string comment; +}; + +struct tok_variable_record +{ + std::vector<std::pair<int,string> > declaration; +}; + +struct tok_typedef_record +{ + std::vector<std::pair<int,string> > declaration; +}; + +struct tok_class_record +{ + std::vector<std::pair<int,string> > declaration; + string name; + string scope; + string file; + string comment; + + std::vector<tok_method_record> public_methods; + std::vector<tok_method_record> protected_methods; + std::vector<tok_variable_record> public_variables; + std::vector<tok_typedef_record> public_typedefs; + std::vector<tok_variable_record> protected_variables; + std::vector<tok_typedef_record> protected_typedefs; + std::vector<tok_class_record> public_inner_classes; + std::vector<tok_class_record> protected_inner_classes; +}; + +// ---------------------------------------------------------------------------------------- + +struct function_record +{ + string name; + string scope; + string declaration; + string file; + string comment; +}; + +struct method_record +{ + string name; + string declaration; + string comment; +}; + +struct variable_record +{ + string declaration; +}; + +struct typedef_record +{ + string declaration; +}; + +struct class_record +{ + string name; + string scope; + string declaration; + string file; + string comment; + + std::vector<method_record> public_methods; + std::vector<variable_record> public_variables; + std::vector<typedef_record> public_typedefs; + + std::vector<method_record> protected_methods; + std::vector<variable_record> protected_variables; + std::vector<typedef_record> protected_typedefs; + + std::vector<class_record> public_inner_classes; + std::vector<class_record> protected_inner_classes; +}; + +// ---------------------------------------------------------------------------------------- + +unsigned long count_newlines ( + const string& str +) +/*! + ensures + - returns the number of '\n' characters inside str +!*/ +{ + unsigned long count = 0; + for (unsigned long i = 0; i < str.size(); ++i) + { + if (str[i] == '\n') + ++count; + } + return count; +} + +// ---------------------------------------------------------------------------------------- + +bool contains_unescaped_newline ( + const string& str +) +/*! + ensures + - returns true if str contains a '\n' character that isn't preceded by a '\' + character. +!*/ +{ + if (str.size() == 0) + return false; + + if (str[0] == '\n') + return true; + + for (unsigned long i = 1; i < str.size(); ++i) + { + if (str[i] == '\n' && str[i-1] != '\\') + return true; + } + + return false; +} + +// ---------------------------------------------------------------------------------------- + +bool is_formal_comment ( + const string& str +) +{ + if (str.size() < 6) + return false; + + if (str[0] == '/' && + str[1] == '*' && + str[2] == '!' && + str[3] != 'P' && + str[3] != 'p' && + str[str.size()-3] == '!' && + str[str.size()-2] == '*' && + str[str.size()-1] == '/' ) + return true; + + return false; +} + +// ---------------------------------------------------------------------------------------- + +string make_scope_string ( + const std::vector<string>& namespaces, + unsigned long exclude_last_num_scopes = 0 +) +{ + string temp; + for (unsigned long i = 0; i + exclude_last_num_scopes < namespaces.size(); ++i) + { + if (namespaces[i].size() == 0) + continue; + + if (temp.size() == 0) + temp = namespaces[i]; + else + temp += "::" + namespaces[i]; + } + return temp; +} + +// ---------------------------------------------------------------------------------------- + +bool looks_like_function_declaration ( + const std::vector<std::pair<int,string> >& declaration +) +{ + + // Check if declaration contains IDENTIFIER ( ) somewhere in it. + bool seen_first_part = false; + bool seen_operator = false; + int local_paren_count = 0; + for (unsigned long i = 1; i < declaration.size(); ++i) + { + if (declaration[i].first == tok_type::KEYWORD && + declaration[i].second == "operator") + { + seen_operator = true; + } + + if (declaration[i].first == tok_type::OTHER && + declaration[i].second == "(" && + (declaration[i-1].first == tok_type::IDENTIFIER || seen_operator)) + { + seen_first_part = true; + } + + if (declaration[i].first == tok_type::OTHER) + { + if ( declaration[i].second == "(") + ++local_paren_count; + else if ( declaration[i].second == ")") + --local_paren_count; + } + } + + if (seen_first_part && local_paren_count == 0) + return true; + else + return false; +} + +// ---------------------------------------------------------------------------------------- + +enum scope_type +{ + public_scope, + protected_scope, + private_scope +}; + + +void process_file ( + istream& fin, + const string& file, + std::vector<tok_function_record>& functions, + std::vector<tok_class_record>& classes +) +/*! + ensures + - scans the given file for global functions and appends any found into functions. + - scans the given file for global classes and appends any found into classes. +!*/ +{ + tok_type tok; + tok.set_stream(fin); + + bool recently_seen_struct_keyword = false; + // true if we have seen the struct keyword and + // we have not seen any identifiers or { characters + + string last_struct_name; + // the name of the last struct we have seen + + bool recently_seen_class_keyword = false; + // true if we have seen the class keyword and + // we have not seen any identifiers or { characters + + string last_class_name; + // the name of the last class we have seen + + bool recently_seen_namespace_keyword = false; + // true if we have seen the namespace keyword and + // we have not seen any identifiers or { characters + + string last_namespace_name; + // the name of the last namespace we have seen + + bool recently_seen_pound_define = false; + // true if we have seen a #define and haven't seen an unescaped newline + + bool recently_seen_preprocessor = false; + // true if we have seen a preprocessor statement and haven't seen an unescaped newline + + bool recently_seen_typedef = false; + // true if we have seen a typedef keyword and haven't seen a ; + + bool recently_seen_paren_0 = false; + // true if we have seen paren_count transition to zero but haven't yet seen a ; or { or + // a new line if recently_seen_pound_define is true. + + bool recently_seen_slots = false; + // true if we have seen the identifier "slots" at a zero scope but haven't seen any + // other identifiers or the ';' or ':' characters. + + bool recently_seen_closing_bracket = false; + // true if we have seen a } and haven't yet seen an IDENTIFIER or ; + + bool recently_seen_new_scope = false; + // true if we have seen the keywords class, namespace, struct, or extern and + // we have not seen the characters {, ), or ; since then + + bool at_top_of_new_scope = false; + // true if we have seen the { that started a new scope but haven't seen anything yet but WHITE_SPACE + + std::vector<string> namespaces; + // a stack to hold the names of the scopes we have entered. This is the classes, structs, and namespaces we enter. + namespaces.push_back(""); // this is the global namespace + + std::stack<scope_type> scope_access; + // If the stack isn't empty then we are inside a class or struct and the top value + // in the stack tells if we are in a public, protected, or private region. + + std::stack<unsigned long> scopes; // a stack to hold current and old scope counts + // the top of the stack counts the number of new scopes (i.e. unmatched { } we have entered + // since we were at a scope where functions can be defined. + // We also maintain the invariant that scopes.size() == namespaces.size() + scopes.push(0); + + std::stack<tok_class_record> class_stack; + // This is a stack where class_stack.top() == the incomplete class record for the class declaration we are + // currently in. + + unsigned long paren_count = 0; + // this is the number of ( we have seen minus the number of ) we have + // seen. + + std::vector<std::pair<int,string> > token_accum; + // Used to accumulate tokens for function and class declarations + + std::vector<std::pair<int,string> > last_full_declaration; + // Once we determine that token_accum has a full declaration in it we copy it into last_full_declaration. + + int type; + string token; + + tok.get_token(type, token); + + while (type != tok_type::END_OF_FILE) + { + switch(type) + { + case tok_type::KEYWORD: // ------------------------------------------ + { + token_accum.push_back(make_pair(type,token)); + + if (token[0] == '#') + recently_seen_preprocessor = true; + + if (token == "class") + { + recently_seen_class_keyword = true; + recently_seen_new_scope = true; + } + else if (token == "struct") + { + recently_seen_struct_keyword = true; + recently_seen_new_scope = true; + } + else if (token == "namespace") + { + recently_seen_namespace_keyword = true; + recently_seen_new_scope = true; + } + else if (token == "extern") + { + recently_seen_new_scope = true; + } + else if (token == "#define") + { + recently_seen_pound_define = true; + } + else if (token == "typedef") + { + recently_seen_typedef = true; + } + else if (recently_seen_pound_define == false) + { + // eat white space + int temp_type; + string temp_token; + if (tok.peek_type() == tok_type::WHITE_SPACE) + tok.get_token(temp_type, temp_token); + + const bool next_is_colon = (tok.peek_type() == tok_type::OTHER && tok.peek_token() == ":"); + if (next_is_colon) + { + // eat the colon + tok.get_token(temp_type, temp_token); + + if (scope_access.size() > 0 && token == "public") + { + scope_access.top() = public_scope; + token_accum.clear(); + last_full_declaration.clear(); + } + else if (scope_access.size() > 0 && token == "protected") + { + scope_access.top() = protected_scope; + token_accum.clear(); + last_full_declaration.clear(); + } + else if (scope_access.size() > 0 && token == "private") + { + scope_access.top() = private_scope; + token_accum.clear(); + last_full_declaration.clear(); + } + } + } + + at_top_of_new_scope = false; + + }break; + + case tok_type::COMMENT: // ------------------------------------------ + { + if (scopes.top() == 0 && last_full_declaration.size() > 0 && is_formal_comment(token) && + paren_count == 0) + { + + // if we are inside a class or struct + if (scope_access.size() > 0) + { + // if we are looking at a comment at the top of a class + if (at_top_of_new_scope) + { + // push an entry for this class into the class_stack + tok_class_record temp; + temp.declaration = last_full_declaration; + temp.file = file; + temp.name = namespaces.back(); + temp.scope = make_scope_string(namespaces,1); + temp.comment = token; + class_stack.push(temp); + } + else if (scope_access.top() == public_scope || scope_access.top() == protected_scope) + { + // This should be a member function. + // Only do anything if the class that contains this member function is + // in the class_stack. + if (class_stack.size() > 0 && class_stack.top().name == namespaces.back() && + looks_like_function_declaration(last_full_declaration)) + { + tok_method_record temp; + + // Check if there is an initialization list inside the declaration and if there is + // then find out where the starting : is located so we can avoid including it in + // the output. + unsigned long pos = last_full_declaration.size(); + long temp_paren_count = 0; + for (unsigned long i = 0; i < last_full_declaration.size(); ++i) + { + if (last_full_declaration[i].first == tok_type::OTHER) + { + if (last_full_declaration[i].second == "(") + ++temp_paren_count; + else if (last_full_declaration[i].second == ")") + --temp_paren_count; + else if (temp_paren_count == 0 && last_full_declaration[i].second == ":") + { + // if this is a :: then ignore it + if (i > 0 && last_full_declaration[i-1].second == ":") + continue; + else if (i+1 < last_full_declaration.size() && last_full_declaration[i+1].second == ":") + continue; + else + { + pos = i; + break; + } + } + } + } + + temp.declaration.assign(last_full_declaration.begin(), last_full_declaration.begin()+pos); + temp.comment = token; + if (scope_access.top() == public_scope) + class_stack.top().public_methods.push_back(temp); + else + class_stack.top().protected_methods.push_back(temp); + } + } + } + else + { + // we should be looking at a global declaration of some kind. + if (looks_like_function_declaration(last_full_declaration)) + { + tok_function_record temp; + + // make sure we never include anything beyond the first closing ) + // if we are looking at a #defined function + unsigned long pos = last_full_declaration.size(); + if (last_full_declaration[0].second == "#define") + { + long temp_paren_count = 0; + for (unsigned long i = 0; i < last_full_declaration.size(); ++i) + { + if (last_full_declaration[i].first == tok_type::OTHER) + { + if (last_full_declaration[i].second == "(") + { + ++temp_paren_count; + } + else if (last_full_declaration[i].second == ")") + { + --temp_paren_count; + if (temp_paren_count == 0) + { + pos = i+1; + break; + } + } + } + } + } + + temp.declaration.assign(last_full_declaration.begin(), last_full_declaration.begin()+pos); + temp.file = file; + temp.scope = make_scope_string(namespaces); + temp.comment = token; + functions.push_back(temp); + } + } + + token_accum.clear(); + last_full_declaration.clear(); + } + + at_top_of_new_scope = false; + }break; + + case tok_type::IDENTIFIER: // ------------------------------------------ + { + if (recently_seen_class_keyword) + { + last_class_name = token; + last_struct_name.clear(); + last_namespace_name.clear(); + } + else if (recently_seen_struct_keyword) + { + last_struct_name = token; + last_class_name.clear(); + last_namespace_name.clear(); + } + else if (recently_seen_namespace_keyword) + { + last_namespace_name = token; + last_class_name.clear(); + last_struct_name.clear(); + } + + if (scopes.top() == 0 && token == "slots") + recently_seen_slots = true; + else + recently_seen_slots = false; + + recently_seen_class_keyword = false; + recently_seen_struct_keyword = false; + recently_seen_namespace_keyword = false; + recently_seen_closing_bracket = false; + at_top_of_new_scope = false; + + token_accum.push_back(make_pair(type,token)); + }break; + + case tok_type::OTHER: // ------------------------------------------ + { + switch(token[0]) + { + case '{': + // if we are entering a new scope + if (recently_seen_new_scope) + { + scopes.push(0); + at_top_of_new_scope = true; + + // if we are entering a class + if (last_class_name.size() > 0) + { + scope_access.push(private_scope); + namespaces.push_back(last_class_name); + } + else if (last_struct_name.size() > 0) + { + scope_access.push(public_scope); + namespaces.push_back(last_struct_name); + } + else if (last_namespace_name.size() > 0) + { + namespaces.push_back(last_namespace_name); + } + else + { + namespaces.push_back(""); + } + } + else + { + scopes.top() += 1; + } + recently_seen_new_scope = false; + recently_seen_class_keyword = false; + recently_seen_struct_keyword = false; + recently_seen_namespace_keyword = false; + recently_seen_paren_0 = false; + + // a { at function scope is an end of a potential declaration + if (scopes.top() == 0) + { + // put token_accum into last_full_declaration + token_accum.swap(last_full_declaration); + } + token_accum.clear(); + break; + + case '}': + if (scopes.top() > 0) + { + scopes.top() -= 1; + } + else if (scopes.size() > 1) + { + scopes.pop(); + + if (scope_access.size() > 0) + scope_access.pop(); + + // If the scope we are leaving is the top class on the class_stack + // then we need to either pop it into its containing class or put it + // into the classes output vector. + if (class_stack.size() > 0 && namespaces.back() == class_stack.top().name) + { + // If this class is a inner_class of another then push it into the + // public_inner_classes or protected_inner_classes field of it's containing class. + if (class_stack.size() > 1) + { + tok_class_record temp = class_stack.top(); + class_stack.pop(); + if (scope_access.size() > 0) + { + if (scope_access.top() == public_scope) + class_stack.top().public_inner_classes.push_back(temp); + else if (scope_access.top() == protected_scope) + class_stack.top().protected_inner_classes.push_back(temp); + } + } + else if (class_stack.size() > 0) + { + classes.push_back(class_stack.top()); + class_stack.pop(); + } + } + + namespaces.pop_back(); + last_full_declaration.clear(); + } + + token_accum.clear(); + recently_seen_closing_bracket = true; + at_top_of_new_scope = false; + break; + + case ';': + // a ; at function scope is an end of a potential declaration + if (scopes.top() == 0) + { + // put token_accum into last_full_declaration + token_accum.swap(last_full_declaration); + } + token_accum.clear(); + + // if we are inside the public area of a class and this ; might be the end + // of a typedef or variable declaration + if (scopes.top() == 0 && scope_access.size() > 0 && + (scope_access.top() == public_scope || scope_access.top() == protected_scope) && + recently_seen_closing_bracket == false) + { + if (recently_seen_typedef) + { + // This should be a typedef inside the public area of a class or struct: + // Only do anything if the class that contains this typedef is in the class_stack. + if (class_stack.size() > 0 && class_stack.top().name == namespaces.back()) + { + tok_typedef_record temp; + temp.declaration = last_full_declaration; + if (scope_access.top() == public_scope) + class_stack.top().public_typedefs.push_back(temp); + else + class_stack.top().protected_typedefs.push_back(temp); + } + + } + else if (recently_seen_paren_0 == false && recently_seen_new_scope == false) + { + // This should be some kind of public variable declaration inside a class or struct: + // Only do anything if the class that contains this member variable is in the class_stack. + if (class_stack.size() > 0 && class_stack.top().name == namespaces.back()) + { + tok_variable_record temp; + temp.declaration = last_full_declaration; + if (scope_access.top() == public_scope) + class_stack.top().public_variables.push_back(temp); + else + class_stack.top().protected_variables.push_back(temp); + } + + } + } + + recently_seen_new_scope = false; + recently_seen_typedef = false; + recently_seen_paren_0 = false; + recently_seen_closing_bracket = false; + recently_seen_slots = false; + at_top_of_new_scope = false; + break; + + case ':': + token_accum.push_back(make_pair(type,token)); + if (recently_seen_slots) + { + token_accum.clear(); + last_full_declaration.clear(); + recently_seen_slots = false; + } + break; + + case '(': + ++paren_count; + token_accum.push_back(make_pair(type,token)); + at_top_of_new_scope = false; + break; + + case ')': + token_accum.push_back(make_pair(type,token)); + + --paren_count; + if (paren_count == 0) + { + recently_seen_paren_0 = true; + if (scopes.top() == 0) + { + last_full_declaration = token_accum; + } + } + + recently_seen_new_scope = false; + at_top_of_new_scope = false; + break; + + default: + token_accum.push_back(make_pair(type,token)); + at_top_of_new_scope = false; + break; + } + }break; + + + case tok_type::WHITE_SPACE: // ------------------------------------------ + { + if (recently_seen_pound_define) + { + if (contains_unescaped_newline(token)) + { + recently_seen_pound_define = false; + recently_seen_paren_0 = false; + recently_seen_preprocessor = false; + + // this is an end of a potential declaration + token_accum.swap(last_full_declaration); + token_accum.clear(); + } + } + + if (recently_seen_preprocessor) + { + if (contains_unescaped_newline(token)) + { + recently_seen_preprocessor = false; + + last_full_declaration.clear(); + token_accum.clear(); + } + } + }break; + + default: // ------------------------------------------ + { + token_accum.push_back(make_pair(type,token)); + at_top_of_new_scope = false; + }break; + } + + + tok.get_token(type, token); + } +} + +// ---------------------------------------------------------------------------------------- + +string get_function_name ( + const std::vector<std::pair<int,string> >& declaration +) +{ + string name; + + bool contains_operator = false; + unsigned long operator_pos = 0; + for (unsigned long i = 0; i < declaration.size(); ++i) + { + if (declaration[i].first == tok_type::KEYWORD && + declaration[i].second == "operator") + { + contains_operator = true; + operator_pos = i; + break; + } + } + + + // find the opening ( for the function + unsigned long paren_pos = 0; + long paren_count = 0; + for (long i = declaration.size()-1; i >= 0; --i) + { + if (declaration[i].first == tok_type::OTHER && + declaration[i].second == ")") + { + ++paren_count; + } + else if (declaration[i].first == tok_type::OTHER && + declaration[i].second == "(") + { + --paren_count; + if (paren_count == 0) + { + paren_pos = i; + break; + } + } + } + + + if (contains_operator) + { + name = declaration[operator_pos].second; + for (unsigned long i = operator_pos+1; i < paren_pos; ++i) + { + if (declaration[i].first == tok_type::IDENTIFIER || declaration[i].first == tok_type::KEYWORD) + { + name += " "; + } + + name += declaration[i].second; + } + } + else + { + // if this is a destructor then include the ~ + if (paren_pos > 1 && declaration[paren_pos-2].second == "~") + name = "~" + declaration[paren_pos-1].second; + else if (paren_pos > 0) + name = declaration[paren_pos-1].second; + + + } + + return name; +} + +// ---------------------------------------------------------------------------------------- + +string pretty_print_declaration ( + const std::vector<std::pair<int,string> >& decl +) +{ + string temp; + long angle_count = 0; + long paren_count = 0; + + if (decl.size() == 0) + return temp; + + temp = decl[0].second; + + + bool just_closed_template = false; + bool in_template = false; + bool last_was_scope_res = false; + bool seen_operator = false; + + if (temp == "operator") + seen_operator = true; + + for (unsigned long i = 1; i < decl.size(); ++i) + { + bool last_was_less_than = false; + if (decl[i-1].first == tok_type::OTHER && decl[i-1].second == "<") + last_was_less_than = true; + + + if (decl[i].first == tok_type::OTHER && decl[i].second == "<" && + (decl[i-1].second != "operator" && ((i>1 && decl[i-2].second != "operator") || decl[i-1].second != "<") )) + ++angle_count; + + if (decl[i-1].first == tok_type::KEYWORD && decl[i-1].second == "template" && + decl[i].first == tok_type::OTHER && decl[i].second == "<") + { + in_template = true; + temp += " <\n "; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == ">") + { + // don't count angle brackets when they are part of an operator + if (decl[i-1].second != "operator" && ((i>1 && decl[i-2].second != "operator") || decl[i-1].second != ">")) + --angle_count; + + if (angle_count == 0 && in_template) + { + temp += "\n >\n"; + just_closed_template = true; + in_template = false; + } + else + { + temp += ">"; + } + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "<") + { + temp += "<"; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == ",") + { + if (in_template || (paren_count == 1 && angle_count == 0)) + temp += ",\n "; + else + temp += ","; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "&") + { + temp += "&"; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == ".") + { + temp += "."; + } + else if (decl[i].first == tok_type::SINGLE_QUOTED_TEXT) + { + temp += decl[i].second; + } + else if (decl[i].first == tok_type::DOUBLE_QUOTED_TEXT) + { + temp += decl[i].second; + } + else if (decl[i-1].first == tok_type::SINGLE_QUOTED_TEXT && decl[i].second == "'") + { + temp += decl[i].second; + } + else if (decl[i-1].first == tok_type::DOUBLE_QUOTED_TEXT && decl[i].second == "\"") + { + temp += decl[i].second; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "[") + { + temp += "["; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "]") + { + temp += "]"; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "-") + { + temp += "-"; + } + else if (decl[i].first == tok_type::NUMBER) + { + if (decl[i-1].second == "=") + temp += " " + decl[i].second; + else + temp += decl[i].second; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "*") + { + temp += "*"; + } + else if (decl[i].first == tok_type::KEYWORD && decl[i].second == "operator") + { + temp += "\noperator"; + seen_operator = true; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == ":" && + (decl[i-1].second == ":" || (i+1<decl.size() && decl[i+1].second == ":") ) ) + { + temp += ":"; + last_was_scope_res = true; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == "(") + { + const bool next_is_paren = (i+1 < decl.size() && decl[i+1].first == tok_type::OTHER && decl[i+1].second == ")"); + + if (paren_count == 0 && next_is_paren == false && in_template == false) + temp += " (\n "; + else + temp += "("; + + ++paren_count; + } + else if (decl[i].first == tok_type::OTHER && decl[i].second == ")") + { + --paren_count; + if (paren_count == 0 && decl[i-1].second != "(" && in_template == false) + temp += "\n)"; + else + temp += ")"; + } + else if (decl[i].first == tok_type::IDENTIFIER && i+1 < decl.size() && + decl[i+1].first == tok_type::OTHER && decl[i+1].second == "(") + { + if (just_closed_template || paren_count != 0 || decl[i-1].second == "~") + temp += decl[i].second; + else if (seen_operator) + temp += " " + decl[i].second; + else + temp += "\n" + decl[i].second; + + just_closed_template = false; + last_was_scope_res = false; + } + else + { + if (just_closed_template || last_was_scope_res || last_was_less_than || + (seen_operator && paren_count == 0 && decl[i].first == tok_type::OTHER ) || + ((decl[i].first == tok_type::KEYWORD || decl[i].first == tok_type::IDENTIFIER) && i>0 && decl[i-1].second == "(")) + temp += decl[i].second; + else + temp += " " + decl[i].second; + + just_closed_template = false; + last_was_scope_res = false; + } + + + + } + + return temp; +} + +// ---------------------------------------------------------------------------------------- + +string format_comment ( + const string& comment, + const unsigned long expand_tabs +) +{ + if (comment.size() <= 6) + return ""; + + string temp = trim(trim(comment.substr(3,comment.size()-6), " \t"), "\n\r"); + + + // if we should expand tabs to spaces + if (expand_tabs != 0) + { + unsigned long column = 0; + string str; + for (unsigned long i = 0; i < temp.size(); ++i) + { + if (temp[i] == '\t') + { + const unsigned long num_spaces = expand_tabs - column%expand_tabs; + column += num_spaces; + str.insert(str.end(), num_spaces, ' '); + } + else if (temp[i] == '\n' || temp[i] == '\r') + { + str += temp[i]; + column = 0; + } + else + { + str += temp[i]; + ++column; + } + } + + // put str into temp + str.swap(temp); + } + + // now figure out what the smallest amount of leading white space is and remove it from each line. + unsigned long num_whitespace = 100000; + + string::size_type pos1 = 0, pos2 = 0; + + while (pos1 != string::npos) + { + // find start of non-white-space + pos2 = temp.find_first_not_of(" \t",pos1); + + // if this is a line of just white space then ignore it + if (pos2 != string::npos && temp[pos2] != '\n' && temp[pos2] != '\r') + { + if (pos2-pos1 < num_whitespace) + num_whitespace = pos2-pos1; + } + + // find end-of-line + pos1 = temp.find_first_of("\n\r", pos2); + // find start of next line + pos2 = temp.find_first_not_of("\n\r", pos1); + pos1 = pos2; + } + + // now remove the leading white space + string temp2; + unsigned long counter = 0; + for (unsigned long i = 0; i < temp.size(); ++i) + { + // if we are looking at a new line + if (temp[i] == '\n' || temp[i] == '\r') + { + counter = 0; + } + else if (counter < num_whitespace) + { + ++counter; + continue; + } + + temp2 += temp[i]; + } + + return temp2; +} + +// ---------------------------------------------------------------------------------------- + +typedef_record convert_tok_typedef_record ( + const tok_typedef_record& rec +) +{ + typedef_record temp; + temp.declaration = pretty_print_declaration(rec.declaration); + return temp; +} + +// ---------------------------------------------------------------------------------------- + +variable_record convert_tok_variable_record ( + const tok_variable_record& rec +) +{ + variable_record temp; + temp.declaration = pretty_print_declaration(rec.declaration); + return temp; +} + +// ---------------------------------------------------------------------------------------- + +method_record convert_tok_method_record ( + const tok_method_record& rec, + const unsigned long expand_tabs +) +{ + method_record temp; + + temp.comment = format_comment(rec.comment, expand_tabs); + temp.name = get_function_name(rec.declaration); + temp.declaration = pretty_print_declaration(rec.declaration); + return temp; +} + +// ---------------------------------------------------------------------------------------- + +class_record convert_tok_class_record ( + const tok_class_record& rec, + const unsigned long expand_tabs +) +{ + class_record crec; + + + crec.scope = rec.scope; + crec.file = rec.file; + crec.comment = format_comment(rec.comment, expand_tabs); + + crec.name.clear(); + + // find the first class token + for (unsigned long i = 0; i+1 < rec.declaration.size(); ++i) + { + if (rec.declaration[i].first == tok_type::KEYWORD && + (rec.declaration[i].second == "class" || + rec.declaration[i].second == "struct" ) + ) + { + crec.name = rec.declaration[i+1].second; + break; + } + } + + crec.declaration = pretty_print_declaration(rec.declaration); + + for (unsigned long i = 0; i < rec.public_typedefs.size(); ++i) + crec.public_typedefs.push_back(convert_tok_typedef_record(rec.public_typedefs[i])); + + for (unsigned long i = 0; i < rec.public_variables.size(); ++i) + crec.public_variables.push_back(convert_tok_variable_record(rec.public_variables[i])); + + for (unsigned long i = 0; i < rec.protected_typedefs.size(); ++i) + crec.protected_typedefs.push_back(convert_tok_typedef_record(rec.protected_typedefs[i])); + + for (unsigned long i = 0; i < rec.protected_variables.size(); ++i) + crec.protected_variables.push_back(convert_tok_variable_record(rec.protected_variables[i])); + + for (unsigned long i = 0; i < rec.public_methods.size(); ++i) + crec.public_methods.push_back(convert_tok_method_record(rec.public_methods[i], expand_tabs)); + + for (unsigned long i = 0; i < rec.protected_methods.size(); ++i) + crec.protected_methods.push_back(convert_tok_method_record(rec.protected_methods[i], expand_tabs)); + + for (unsigned long i = 0; i < rec.public_inner_classes.size(); ++i) + crec.public_inner_classes.push_back(convert_tok_class_record(rec.public_inner_classes[i], expand_tabs)); + + for (unsigned long i = 0; i < rec.protected_inner_classes.size(); ++i) + crec.protected_inner_classes.push_back(convert_tok_class_record(rec.protected_inner_classes[i], expand_tabs)); + + + return crec; +} + +// ---------------------------------------------------------------------------------------- + +function_record convert_tok_function_record ( + const tok_function_record& rec, + const unsigned long expand_tabs +) +{ + function_record temp; + + temp.scope = rec.scope; + temp.file = rec.file; + temp.comment = format_comment(rec.comment, expand_tabs); + temp.name = get_function_name(rec.declaration); + temp.declaration = pretty_print_declaration(rec.declaration); + + return temp; +} + +// ---------------------------------------------------------------------------------------- + +void convert_to_normal_records ( + const std::vector<tok_function_record>& tok_functions, + const std::vector<tok_class_record>& tok_classes, + const unsigned long expand_tabs, + std::vector<function_record>& functions, + std::vector<class_record>& classes +) +{ + functions.clear(); + classes.clear(); + + + for (unsigned long i = 0; i < tok_functions.size(); ++i) + { + functions.push_back(convert_tok_function_record(tok_functions[i], expand_tabs)); + } + + + for (unsigned long i = 0; i < tok_classes.size(); ++i) + { + classes.push_back(convert_tok_class_record(tok_classes[i], expand_tabs)); + } + + +} + +// ---------------------------------------------------------------------------------------- + +string add_entity_ref (const string& str) +{ + string temp; + for (unsigned long i = 0; i < str.size(); ++i) + { + if (str[i] == '&') + temp += "&"; + else if (str[i] == '<') + temp += "<"; + else if (str[i] == '>') + temp += ">"; + else + temp += str[i]; + } + return temp; +} + +// ---------------------------------------------------------------------------------------- + +string flip_slashes (string str) +{ + for (unsigned long i = 0; i < str.size(); ++i) + { + if (str[i] == '\\') + str[i] = '/'; + } + return str; +} + +// ---------------------------------------------------------------------------------------- + +void write_as_xml ( + const function_record& rec, + ostream& fout +) +{ + fout << " <function>\n"; + fout << " <name>" << add_entity_ref(rec.name) << "</name>\n"; + fout << " <scope>" << add_entity_ref(rec.scope) << "</scope>\n"; + fout << " <declaration>" << add_entity_ref(rec.declaration) << "</declaration>\n"; + fout << " <file>" << flip_slashes(add_entity_ref(rec.file)) << "</file>\n"; + fout << " <comment>" << add_entity_ref(rec.comment) << "</comment>\n"; + fout << " </function>\n"; +} + +// ---------------------------------------------------------------------------------------- + +void write_as_xml ( + const class_record& rec, + ostream& fout, + unsigned long indent +) +{ + const string pad(indent, ' '); + + fout << pad << "<class>\n"; + fout << pad << " <name>" << add_entity_ref(rec.name) << "</name>\n"; + fout << pad << " <scope>" << add_entity_ref(rec.scope) << "</scope>\n"; + fout << pad << " <declaration>" << add_entity_ref(rec.declaration) << "</declaration>\n"; + fout << pad << " <file>" << flip_slashes(add_entity_ref(rec.file)) << "</file>\n"; + fout << pad << " <comment>" << add_entity_ref(rec.comment) << "</comment>\n"; + + + if (rec.public_typedefs.size() > 0) + { + fout << pad << " <public_typedefs>\n"; + for (unsigned long i = 0; i < rec.public_typedefs.size(); ++i) + { + fout << pad << " <typedef>" << add_entity_ref(rec.public_typedefs[i].declaration) << "</typedef>\n"; + } + fout << pad << " </public_typedefs>\n"; + } + + + if (rec.public_variables.size() > 0) + { + fout << pad << " <public_variables>\n"; + for (unsigned long i = 0; i < rec.public_variables.size(); ++i) + { + fout << pad << " <variable>" << add_entity_ref(rec.public_variables[i].declaration) << "</variable>\n"; + } + fout << pad << " </public_variables>\n"; + } + + if (rec.protected_typedefs.size() > 0) + { + fout << pad << " <protected_typedefs>\n"; + for (unsigned long i = 0; i < rec.protected_typedefs.size(); ++i) + { + fout << pad << " <typedef>" << add_entity_ref(rec.protected_typedefs[i].declaration) << "</typedef>\n"; + } + fout << pad << " </protected_typedefs>\n"; + } + + + if (rec.protected_variables.size() > 0) + { + fout << pad << " <protected_variables>\n"; + for (unsigned long i = 0; i < rec.protected_variables.size(); ++i) + { + fout << pad << " <variable>" << add_entity_ref(rec.protected_variables[i].declaration) << "</variable>\n"; + } + fout << pad << " </protected_variables>\n"; + } + + + if (rec.public_methods.size() > 0) + { + fout << pad << " <public_methods>\n"; + for (unsigned long i = 0; i < rec.public_methods.size(); ++i) + { + fout << pad << " <method>\n"; + fout << pad << " <name>" << add_entity_ref(rec.public_methods[i].name) << "</name>\n"; + fout << pad << " <declaration>" << add_entity_ref(rec.public_methods[i].declaration) << "</declaration>\n"; + fout << pad << " <comment>" << add_entity_ref(rec.public_methods[i].comment) << "</comment>\n"; + fout << pad << " </method>\n"; + } + fout << pad << " </public_methods>\n"; + } + + + if (rec.protected_methods.size() > 0) + { + fout << pad << " <protected_methods>\n"; + for (unsigned long i = 0; i < rec.protected_methods.size(); ++i) + { + fout << pad << " <method>\n"; + fout << pad << " <name>" << add_entity_ref(rec.protected_methods[i].name) << "</name>\n"; + fout << pad << " <declaration>" << add_entity_ref(rec.protected_methods[i].declaration) << "</declaration>\n"; + fout << pad << " <comment>" << add_entity_ref(rec.protected_methods[i].comment) << "</comment>\n"; + fout << pad << " </method>\n"; + } + fout << pad << " </protected_methods>\n"; + } + + + if (rec.public_inner_classes.size() > 0) + { + fout << pad << " <public_inner_classes>\n"; + for (unsigned long i = 0; i < rec.public_inner_classes.size(); ++i) + { + write_as_xml(rec.public_inner_classes[i], fout, indent+4); + } + fout << pad << " </public_inner_classes>\n"; + } + + if (rec.protected_inner_classes.size() > 0) + { + fout << pad << " <protected_inner_classes>\n"; + for (unsigned long i = 0; i < rec.protected_inner_classes.size(); ++i) + { + write_as_xml(rec.protected_inner_classes[i], fout, indent+4); + } + fout << pad << " </protected_inner_classes>\n"; + } + + + fout << pad << "</class>\n"; +} + +// ---------------------------------------------------------------------------------------- + +void save_to_xml_file ( + const std::vector<function_record>& functions, + const std::vector<class_record>& classes +) +{ + ofstream fout("output.xml"); + + fout << "<!-- This XML file was generated using the htmlify tool available from http://dlib.net. -->" << endl; + fout << "<code>" << endl; + + fout << " <classes>" << endl; + for (unsigned long i = 0; i < classes.size(); ++i) + { + write_as_xml(classes[i], fout, 4); + fout << "\n"; + } + fout << " </classes>\n\n" << endl; + + + fout << " <global_functions>" << endl; + for (unsigned long i = 0; i < functions.size(); ++i) + { + write_as_xml(functions[i], fout); + fout << "\n"; + } + fout << " </global_functions>" << endl; + + fout << "</code>" << endl; +} + +// ---------------------------------------------------------------------------------------- + +void generate_xml_markup( + const cmd_line_parser<char>::check_1a_c& parser, + const std::string& filter, + const unsigned long search_depth, + const unsigned long expand_tabs +) +{ + + // first figure out which files should be processed + std::vector<std::pair<string,string> > files; + obtain_list_of_files(parser, filter, search_depth, files); + + + std::vector<tok_function_record> tok_functions; + std::vector<tok_class_record> tok_classes; + + for (unsigned long i = 0; i < files.size(); ++i) + { + ifstream fin(files[i].second.c_str()); + if (!fin) + { + cerr << "Error opening file: " << files[i].second << endl; + return; + } + process_file(fin, files[i].first, tok_functions, tok_classes); + } + + std::vector<function_record> functions; + std::vector<class_record> classes; + + convert_to_normal_records(tok_functions, tok_classes, expand_tabs, functions, classes); + + save_to_xml_file(functions, classes); +} + +// ---------------------------------------------------------------------------------------- + diff --git a/ml/dlib/tools/htmlify/to_xml.h b/ml/dlib/tools/htmlify/to_xml.h new file mode 100644 index 000000000..4bdf3f00e --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml.h @@ -0,0 +1,22 @@ +#ifndef DLIB_HTMLIFY_TO_XmL_H__ +#define DLIB_HTMLIFY_TO_XmL_H__ + +#include "dlib/cmd_line_parser.h" +#include <string> + +void generate_xml_markup( + const dlib::cmd_line_parser<char>::check_1a_c& parser, + const std::string& filter, + const unsigned long search_depth, + const unsigned long expand_tabs +); +/*! + ensures + - reads all the files indicated by the parser arguments and converts them + to XML. The output will be stored in the output.xml file. + - if (expand_tabs != 0) then + - tabs will be replaced with expand_tabs spaces inside comment blocks +!*/ + +#endif // DLIB_HTMLIFY_TO_XmL_H__ + diff --git a/ml/dlib/tools/htmlify/to_xml_example/bigminus.gif b/ml/dlib/tools/htmlify/to_xml_example/bigminus.gif Binary files differnew file mode 100644 index 000000000..aea8e5c01 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/bigminus.gif diff --git a/ml/dlib/tools/htmlify/to_xml_example/bigplus.gif b/ml/dlib/tools/htmlify/to_xml_example/bigplus.gif Binary files differnew file mode 100644 index 000000000..6bee68e21 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/bigplus.gif diff --git a/ml/dlib/tools/htmlify/to_xml_example/example.xml b/ml/dlib/tools/htmlify/to_xml_example/example.xml new file mode 100644 index 000000000..472a4a5e1 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/example.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<?xml-stylesheet type="text/xsl" href="stylesheet.xsl"?> + +<doc> + <title>Documented Code</title> + <body from_file="output.xml"/> +</doc> + diff --git a/ml/dlib/tools/htmlify/to_xml_example/minus.gif b/ml/dlib/tools/htmlify/to_xml_example/minus.gif Binary files differnew file mode 100644 index 000000000..1deac2fe1 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/minus.gif diff --git a/ml/dlib/tools/htmlify/to_xml_example/output.xml b/ml/dlib/tools/htmlify/to_xml_example/output.xml new file mode 100644 index 000000000..95e4de6ae --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/output.xml @@ -0,0 +1,49 @@ +<!-- This XML file was generated using the htmlify tool available from http://dlib.net. --> +<code> + <classes> + <class> + <name>test</name> + <scope></scope> + <declaration>class test</declaration> + <file>test.cpp</file> + <comment>WHAT THIS OBJECT REPRESENTS + This is a simple test class that doesn't do anything</comment> + <public_typedefs> + <typedef>typedef int type</typedef> + </public_typedefs> + <public_methods> + <method> + <name>test</name> + <declaration>test()</declaration> + <comment>ensures + - constructs a test object</comment> + </method> + <method> + <name>print</name> + <declaration>void +print() const</declaration> + <comment>ensures + - prints a message to the screen</comment> + </method> + </public_methods> + </class> + + </classes> + + + <global_functions> + <function> + <name>add_numbers</name> + <scope></scope> + <declaration>int +add_numbers ( + int a, + int b +)</declaration> + <file>test.cpp</file> + <comment>ensures + - returns a + b</comment> + </function> + + </global_functions> +</code> diff --git a/ml/dlib/tools/htmlify/to_xml_example/plus.gif b/ml/dlib/tools/htmlify/to_xml_example/plus.gif Binary files differnew file mode 100644 index 000000000..2d15c1417 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/plus.gif diff --git a/ml/dlib/tools/htmlify/to_xml_example/stylesheet.xsl b/ml/dlib/tools/htmlify/to_xml_example/stylesheet.xsl new file mode 100644 index 000000000..7a44862a3 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/stylesheet.xsl @@ -0,0 +1,354 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> + +<!-- + To the extent possible under law, Davis E King has waived all copyright and + related or neighboring rights to dlib documentation (XML, HTML, and XSLT files). + This work is published from United States. +--> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes' /> + + + <!-- ************************************************************************* --> + + <xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz </xsl:variable> + <xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ </xsl:variable> + + <!-- ************************************************************************* --> + + <xsl:template match="/doc"> + <html> + <head> + <title> + <xsl:if test="title"> + <xsl:value-of select="title" /> + </xsl:if> + </title> + + + <!-- [client side code for collapsing and unfolding branches] --> + <script language="JavaScript"> + + // --------------------------------------------- + // --- Name: Easy DHTML Treeview -- + // --- Author: D.D. de Kerf -- + // --- Version: 0.2 Date: 13-6-2001 -- + // --------------------------------------------- + function Toggle(node) + { + // Unfold the branch if it isn't visible + var next_node = node.nextSibling; + if (next_node.style.display == 'none') + { + // Change the image (if there is an image) + if (node.childNodes.length > 0) + { + if (node.childNodes.length > 0) + { + if (node.childNodes.item(0).nodeName == "IMG") + { + node.childNodes.item(0).src = "minus.gif"; + } + } + } + + next_node.style.display = 'block'; + } + // Collapse the branch if it IS visible + else + { + // Change the image (if there is an image) + if (node.childNodes.length > 0) + { + if (node.childNodes.length > 0) + { + if (node.childNodes.item(0).nodeName == "IMG") + { + node.childNodes.item(0).src = "plus.gif"; + } + } + } + + next_node.style.display = 'none'; + } + + } + function BigToggle(node) + { + // Unfold the branch if it isn't visible + var next_node = node.nextSibling; + if (next_node.style.display == 'none') + { + // Change the image (if there is an image) + if (node.childNodes.length > 0) + { + if (node.childNodes.length > 0) + { + if (node.childNodes.item(0).nodeName == "IMG") + { + node.childNodes.item(0).src = "bigminus.gif"; + } + } + } + + next_node.style.display = 'block'; + } + // Collapse the branch if it IS visible + else + { + // Change the image (if there is an image) + if (node.childNodes.length > 0) + { + if (node.childNodes.length > 0) + { + if (node.childNodes.item(0).nodeName == "IMG") + { + node.childNodes.item(0).src = "bigplus.gif"; + } + } + } + + next_node.style.display = 'none'; + } + + } + </script> + + <style type="text/css"> + pre {margin:0px;} + + ul.tree li { list-style: none; margin-left:10px;} + ul.tree { margin:0px; padding:0px; margin-left:5px; font-size:0.95em; } + ul.tree li ul { margin-left:10px; padding:0px; } + + div#component { + background-color:white; + border: 2px solid rgb(102,102,102); + text-align:left; + margin-top: 1.5em; + padding: 0.7em; + } + + div#function { + background-color:white; + border: 2px solid rgb(102,102,255); + text-align:left; + margin-top: 0.3em; + padding: 0.3em; + } + + div#class { + background-color:white; + border: 2px solid rgb(255,102,102); + text-align:left; + margin-top: 0.3em; + padding: 0.3em; + } + + </style> + </head> + <body> + <xsl:if test="title"> + <center><h1> <xsl:value-of select="title" /> </h1></center> + </xsl:if> + <xsl:apply-templates select="body"/> + </body> + </html> + </xsl:template> + + + + + + <!-- ************************************************************************* --> + + <xsl:template match="body"> + <xsl:choose> + <xsl:when test="@from_file"> + <xsl:apply-templates select="document(@from_file)"/> + <xsl:apply-templates/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- ************************************************************************* --> + <!-- ************************************************************************* --> + <!-- XSLT for dealing with <code> blocks generated by the htmlify to-xml option --> + <!-- ************************************************************************* --> + <!-- ************************************************************************* --> + + <xsl:template match="code"> + + <h1>Classes and Structs:</h1> + <xsl:for-each select="classes/class"> + <xsl:sort select="translate(concat(name,.),$lcletters, $ucletters)"/> + <xsl:apply-templates select="."/> + </xsl:for-each> + + <h1>Global Functions:</h1> + <xsl:for-each select="global_functions/function"> + <xsl:sort select="translate(concat(name,.),$lcletters, $ucletters)"/> + <div id="function"> + <a onclick="Toggle(this)" style="cursor: pointer"><img src="plus.gif" border="0"/><font color="blue"> + <u><b><xsl:value-of select="name"/>()</b></u></font></a> + <div style="display:none;"> + <br/> + <xsl:if test="scope != ''"> + <u>Scope</u>: <xsl:value-of select="scope"/> <br/> + </xsl:if> + <u>File</u>: <xsl:value-of select="file"/> <br/><br/> + <div style="margin-left:1.5em"> + <pre style="font-size:1.1em;"><xsl:value-of select="declaration"/>;</pre> + <font color="#009900"><pre><xsl:value-of select="comment"/></pre></font> + </div> + <br/> + </div> + </div> + </xsl:for-each> + + </xsl:template> + + <!-- ************************************************************************* --> + + <xsl:template match="class"> + <div id="class"> + <a onclick="Toggle(this)" style="cursor: pointer"><img src="plus.gif" border="0"/><font color="blue"> + <u><b><xsl:value-of select="name"/></b></u></font></a> + <div style="display:none;"> + <br/> + <xsl:if test="scope != ''"> + <u>Scope</u>: <xsl:value-of select="scope"/> <br/> + </xsl:if> + <u>File</u>: <xsl:value-of select="file"/> <br/><br/> + <div style="margin-left:1.5em"> + <pre style="font-size:1.1em;"><xsl:value-of select="declaration"/>;</pre> <br/> + <font color="#009900"><pre><xsl:value-of select="comment"/></pre></font> <br/> + </div> + + <xsl:if test="protected_typedefs"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Protected Typedefs</u></font></a> + <div style="display:none;"> + <ul> + <xsl:for-each select="protected_typedefs/typedef"> + <li><xsl:value-of select="."/>;</li> + </xsl:for-each> + </ul> + </div> + <br/> + </xsl:if> + + <xsl:if test="public_typedefs"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0" style="size:2em"/><font color="blue"> + <u style="font-size:2em">Public Typedefs</u></font></a> + <div style="display:none;"> + <ul> + <xsl:for-each select="public_typedefs/typedef"> + <li><xsl:value-of select="."/>;</li> + </xsl:for-each> + </ul> + </div> + <br/> + </xsl:if> + + <xsl:if test="protected_variables"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Protected Variables</u></font></a> + <div style="display:none;"> + <ul> + <xsl:for-each select="protected_variables/variable"> + <li><xsl:value-of select="."/>;</li> + </xsl:for-each> + </ul> + </div> + <br/> + </xsl:if> + + <xsl:if test="public_variables"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Public Variables</u></font></a> + <div style="display:none;"> + <ul> + <xsl:for-each select="public_variables/variable"> + <li><xsl:value-of select="."/>;</li> + </xsl:for-each> + </ul> + </div> + <br/> + </xsl:if> + + <xsl:if test="protected_methods"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Protected Methods</u></font></a> + <div style="display:none;"> + <xsl:for-each select="protected_methods/method"> + <div id="function"> + <u>Method Name</u>: <b><xsl:value-of select="name"/></b> <br/><br/> + <div style="margin-left:1.5em"> + <pre style="font-size:1.1em;"><xsl:value-of select="declaration"/>;</pre> + <font color="#009900"><pre><xsl:value-of select="comment"/></pre></font> <br/> + </div> + </div> + </xsl:for-each> + </div> + <br/> + </xsl:if> + + <xsl:if test="public_methods"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Public Methods</u></font></a> + <div style="display:none;"> + <xsl:for-each select="public_methods/method"> + <div id="function"> + <u>Method Name</u>: <b><xsl:value-of select="name"/></b> <br/><br/> + <div style="margin-left:1.5em"> + <pre style="font-size:1.1em;"><xsl:value-of select="declaration"/>;</pre> + <font color="#009900"><pre><xsl:value-of select="comment"/></pre></font> <br/> + </div> + </div> + </xsl:for-each> + </div> + <br/> + </xsl:if> + + <xsl:if test="protected_inner_classes"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Protected Inner Classes</u></font></a> + <div style="display:none;"> + <xsl:for-each select="protected_inner_classes/class"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </div> + <br/> + </xsl:if> + + <xsl:if test="public_inner_classes"> + <a onclick="BigToggle(this)" style="cursor: pointer"><img src="bigplus.gif" border="0"/><font color="blue"> + <u style="font-size:2em">Public Inner Classes</u></font></a> + <div style="display:none;"> + <xsl:for-each select="public_inner_classes/class"> + <xsl:apply-templates select="."/> + </xsl:for-each> + </div> + <br/> + </xsl:if> + + </div> + </div> + </xsl:template> + + + <!-- ************************************************************************* --> + <!-- ************************************************************************* --> + <!-- ************************************************************************* --> + <!-- ************************************************************************* --> + + + + +</xsl:stylesheet> diff --git a/ml/dlib/tools/htmlify/to_xml_example/test.cpp b/ml/dlib/tools/htmlify/to_xml_example/test.cpp new file mode 100644 index 000000000..edbdfff54 --- /dev/null +++ b/ml/dlib/tools/htmlify/to_xml_example/test.cpp @@ -0,0 +1,78 @@ +#include <iostream> + +// ---------------------------------------------------------------------------------------- + +using namespace std; + +// ---------------------------------------------------------------------------------------- + +class test +{ + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple test class that doesn't do anything + !*/ + +public: + + typedef int type; + + test (); + /*! + ensures + - constructs a test object + !*/ + + void print () const; + /*! + ensures + - prints a message to the screen + !*/ + +}; + +// ---------------------------------------------------------------------------------------- + +test::test() {} + +void test::print() const +{ + cout << "A message!" << endl; +} + +// ---------------------------------------------------------------------------------------- + +int add_numbers ( + int a, + int b +) +/*! + ensures + - returns a + b +!*/ +{ + return a + b; +} + +// ---------------------------------------------------------------------------------------- + +void a_function ( +) +/*!P + This is a function which won't show up in the output of htmlify --to-xml + because of the presence of the P in the above /*!P above. +!*/ +{ +} + +// ---------------------------------------------------------------------------------------- + +int main() +{ + test a; + a.print(); +} + +// ---------------------------------------------------------------------------------------- + + |