marks_maker.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : marks_maker                                                       *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    Turns a link database in HOOPLE format into a web page, when given a     *
00009 *  suitable template file.  The template file must have the phrase:           *
00010 *        $INSERT_LINKS_HERE                                                   *
00011 *  at the point where the generated links are supposed to be stored.          *
00012 *                                                                             *
00013 *******************************************************************************
00014 * Copyright (c) 2005-$now By Author.  This program is free software; you can  *
00015 * redistribute it and/or modify it under the terms of the GNU General Public  *
00016 * License as published by the Free Software Foundation; either version 2 of   *
00017 * the License or (at your option) any later version.  This is online at:      *
00018 *     http://www.fsf.org/copyleft/gpl.html                                    *
00019 * Please send any updates to: fred@gruntose.com                               *
00020 \*****************************************************************************/
00021 
00022 #include "bookmark_tree.cpp"
00023 
00024 #include <basis/function.h>
00025 #include <basis/guards.h>
00026 #include <basis/istring.h>
00027 #include <opsystem/application_shell.h>
00028 #include <opsystem/byte_filer.h>
00029 #include <opsystem/command_line.h>
00030 #include <loggers/file_logger.h>
00031 #include <opsystem/filename.h>
00032 #include <data_struct/static_memory_gremlin.h>
00033 #include <textual/list_parsing.h>
00034 
00035 using namespace nodes;
00036 
00037 //#define DEBUG_MARKS
00038   // uncomment to have more debugging noise.
00039 
00040 #undef BASE_LOG
00041 #define BASE_LOG(s) program_wide_logger().log(s)
00042 #undef LOG
00043 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), \
00044    isprintf("line %d: ", _categories._line_number) + s)
00045 
00046 const int MAX_FILE_SIZE = 4 * MEGABYTE;
00047   // the largest file we'll read.
00048 
00050 
00051 class marks_maker : public application_shell
00052 {
00053 public:
00054   marks_maker()
00055       : application_shell(static_class_name()), _need_closure(false) {}
00056   IMPLEMENT_CLASS_NAME("marks_maker");
00057   virtual int execute();
00058   int print_instructions(const filename &program_name);
00059 
00060   int write_marks_page(const istring &output_filename,
00061           const istring &template_filename);
00062     // given a tree of links, this writes out a web page to "output_filename"
00063     // using a template file "template_filename".
00064 
00065 private:
00066   bookmark_tree _categories;  // our tree of categories.
00067   bool _need_closure;  // true if our <div> needs a closure.
00068 
00069 //this needs to gather any strings that would have gone into functions.
00070 //instead, they need to be written into the current node's string.
00071 //when a new function def would be seen, then we need to push a new node
00072 //for accumulating the text.
00073 
00074   // these handle outputting text for categories and links.
00075   void write_category(inner_mark_tree *node, istring &output);
00076   void write_link(inner_mark_tree *node, const link_record &linko,
00077          istring &output);
00078 };
00079 
00081 
00082 int marks_maker::print_instructions(const filename &program_name)
00083 {
00084   isprintf to_show("%s:\n\
00085 This program needs three filenames as command line parameters.  The -i flag\n\
00086 is used to specify the input filename, the -t flag specifies a template web\n\
00087 page which is used as the wrapper around the links, and the -o flag specifies\n\
00088 the web page to be created.  The input file is expected to be in the HOOPLE\n\
00089 link database format.  The output file will be created from the template file\n\
00090 by finding the phrase $INSERT_LINKS_HERE in it and replacing that with html\n\
00091 formatted link and categories from the input file.  Another tag of $TODAYS_DATE\n\
00092 will be replaced with the date when the output file is regenerated.\n\
00093 The HOOPLE link format is documented here:\n\
00094     http://hoople.org/guides/link_database/format_manifesto.txt\n\
00095 ", program_name.basename().raw().s(), program_name.basename().raw().s());
00096   program_wide_logger().log(to_show.s());
00097   return 12;
00098 }
00099 
00100 void marks_maker::write_category(inner_mark_tree *node, istring &output)
00101 {
00102   FUNCDEF("write_category");
00103   // calculate proper heading number.
00104   int heading_num = node->depth();
00105   if (heading_num < 1) heading_num = 1;
00106   else if (heading_num > 2) heading_num = 2;
00107   istring heading = isprintf("%d", heading_num);
00108 
00109   if (_need_closure) {
00110     output += "</div>";
00111     output += log_base::platform_ending();
00112     _need_closure = false;
00113   }
00114 
00115   // add formatting to indent appropriately...
00116   int spaces = 4 * node->depth();
00117   output += isprintf("<div style=\"margin-left: %d0px;\">", spaces);
00118   output += log_base::platform_ending();
00119   _need_closure = true;
00120 
00121   output += "<h";
00122   output += heading;
00123   output += ">";
00124   output += node->name();
00125   output += "</h";
00126   output += heading;
00127   output += ">";
00128   output += log_base::platform_ending();
00129 }
00130 
00131 void marks_maker::write_link(inner_mark_tree *formal(node),
00132     const link_record &linko, istring &output)
00133 {
00134   FUNCDEF("write_link");
00135   // write an html link definition.
00136   if (!linko._url) {
00137     // this just appears to be a comment line.
00138 
00139     if (!linko._description) return;  // it's a nothing line.
00140 
00141     output += linko._description;
00142     output += "<br>";
00143     output += log_base::platform_ending();
00144     return;
00145   }
00146 
00147 //hmmm: move
00148 const int MAX_URL_DISPLAYED = 58;
00149 const int MAX_DESCRIP_DISPLAYED = 72;
00150 
00151 //hmmm...  this is chopping in the middle; would it look more normal
00152 //         to just snap the whole end off?
00153   istring chomped_url = linko._url;
00154   if (chomped_url.length() > MAX_URL_DISPLAYED) {
00155     chomped_url.zap(MAX_URL_DISPLAYED / 2,
00156         chomped_url.length() - MAX_URL_DISPLAYED / 2 - 1);
00157     chomped_url.insert(MAX_URL_DISPLAYED / 2, "...");
00158   }
00159 
00160 //hmmm: this is chopping the tail off, which seems reasonable for a
00161 //      long description.
00162   istring description = linko._description;
00163   if (description.length() > MAX_DESCRIP_DISPLAYED) {
00164     description.zap(MAX_DESCRIP_DISPLAYED - 1, description.end());
00165     description += "...";
00166   }
00167 
00168   output += "<li>";
00169   output += description + "&nbsp;&nbsp;&nbsp;";
00170   output += istring("(") + chomped_url + ")" + "&nbsp;&nbsp;&nbsp;";
00171   output += "<a href=\"javascript:open_mark('";
00172   output += linko._url;
00173   output += "')\">";
00174   output += "[launch]";
00175   output += "</a>&nbsp;&nbsp;<a href=\"";
00176   output += linko._url;
00177   output += "\">";
00178   output += "[go-to]";
00179   output += "</a></li>";
00180   output += log_base::platform_ending();
00181 }
00182 
00183 int marks_maker::execute()
00184 {
00185   FUNCDEF("execute");
00186   SET_DEFAULT_COMBO_LOGGER;
00187 
00188   command_line cmds(__argc, __argv);  // process the command line parameters.
00189   istring input_filename;  // we'll store our link database name here.
00190   istring output_filename;  // where the web page we're creating goes.
00191   istring template_filename;  // the wrapper html code that we'll stuff.
00192   if (!cmds.get_value('i', input_filename, false))
00193     return print_instructions(cmds.program_name());
00194   if (!cmds.get_value('o', output_filename, false))
00195     return print_instructions(cmds.program_name());
00196   if (!cmds.get_value('t', template_filename, false))
00197     return print_instructions(cmds.program_name());
00198 
00199   BASE_LOG(istring("input file: ") + input_filename);
00200   BASE_LOG(istring("output file: ") + output_filename);
00201   BASE_LOG(istring("template file: ") + template_filename);
00202 
00203   filename outname(output_filename);
00204   if (outname.exists()) {
00205     non_continuable_error(class_name(), func, istring("the output file ")
00206         + output_filename + " already exists.  It would be over-written if "
00207         "we continued.");
00208   }
00209 
00210   int ret = _categories.read_csv_file(input_filename);
00211   if (ret) return ret;
00212 
00213   ret = write_marks_page(output_filename, template_filename);
00214   if (ret) return ret;
00215   
00216   return 0;
00217 }
00218 
00219 int marks_maker::write_marks_page(const istring &output_filename,
00220     const istring &template_filename)
00221 {
00222   FUNCDEF("write_marks_page");
00223   istring long_string;
00224     // this is our accumulator of links.  it is the semi-final result that will
00225     // be injected into the template file.
00226 
00227   long_string += "<script type=\"text/javascript\">\n";
00228   long_string += "<!--\n";
00229 
00230   long_string += "function open_mark(url) {\n";
00231   long_string += "  winner = window.open(url, url, '');\n";
00232   long_string += "  winner.focus();\n";
00233   long_string += "}\n";
00234 
00235   long_string += "//-->\n";
00236   long_string += "</script>\n";
00237 
00238   // traverse the tree in prefix order.
00239   tree::iterator itty = _categories.access_root().start(tree::prefix);
00240   tree *curr = NIL;
00241   while ( (curr = itty.next()) ) {
00242     inner_mark_tree *nod = (inner_mark_tree *)curr;
00243     // print out the category on this node.
00244     write_category(nod, long_string);
00245 
00246     // print the link for all of the ones stored at this node.
00247     for (int i = 0; i < nod->_links.elements(); i++) {
00248       link_record *lin = nod->_links.borrow(i);
00249       write_link(nod, *lin, long_string);
00250     }
00251   }
00252 
00253   if (_need_closure) {
00254     long_string += "</div>";
00255     long_string += log_base::platform_ending();
00256     _need_closure = false;
00257   }
00258 
00259   byte_filer template_file(template_filename, "r");
00260   istring full_template;
00261   if (!template_file.good())
00262     non_continuable_error(class_name(), func, "the template file could not be opened");
00263   template_file.read(full_template, MAX_FILE_SIZE);
00264   template_file.close();
00265 
00266   // replace the tag with the long string we created.
00267   bool found_it = full_template.replace("$INSERT_LINKS_HERE", long_string);
00268   if (!found_it)
00269     non_continuable_error(class_name(), func, "the template file is missing "
00270         "the insertion point");
00271   full_template.replace("$TODAYS_DATE", timestamp(false, true));
00272 
00273   filename outname(output_filename);
00274   byte_filer output_file(output_filename, "w");
00275   if (!output_file.good())
00276     non_continuable_error(class_name(), func, "the output file could not be opened");
00277   // write the newly generated web page out now.
00278   output_file.write(full_template);
00279   output_file.close();
00280 
00281 // show the tree.
00282 //  BASE_LOG("");
00283 //  BASE_LOG(_categories.access_root().text_form());
00284 
00285   BASE_LOG(isprintf("wrote %d links in %d categories.",
00286       _categories.link_count(), _categories.category_count()));
00287   BASE_LOG("");
00288 
00289   return 0;
00290 }
00291 
00293 
00294 HOOPLE_MAIN(marks_maker, )
00295 
00296 #ifdef __BUILD_STATIC_APPLICATION__
00297   // static dependencies found by buildor_gen_deps.sh:
00298   #include <basis/array.cpp>
00299   #include <basis/byte_array.cpp>
00300   #include <basis/callstack_tracker.cpp>
00301   #include <basis/chaos.cpp>
00302   #include <basis/convert_utf.cpp>
00303   #include <basis/definitions.cpp>
00304   #include <basis/earth_time.cpp>
00305   #include <basis/guards.cpp>
00306   #include <basis/istring.cpp>
00307   #include <basis/log_base.cpp>
00308   #include <basis/memory_checker.cpp>
00309   #include <basis/mutex.cpp>
00310   #include <basis/object_base.cpp>
00311   #include <basis/outcome.cpp>
00312   #include <basis/packable.cpp>
00313   #include <basis/portable.cpp>
00314   #include <basis/sequence.cpp>
00315   #include <basis/set.cpp>
00316   #include <basis/utility.cpp>
00317   #include <basis/version_record.cpp>
00318   #include <data_struct/amorph.cpp>
00319   #include <data_struct/bit_vector.cpp>
00320   #include <data_struct/byte_hasher.cpp>
00321   #include <data_struct/configurator.cpp>
00322   #include <data_struct/hash_table.cpp>
00323   #include <data_struct/pointer_hash.cpp>
00324   #include <data_struct/stack.cpp>
00325   #include <data_struct/static_memory_gremlin.cpp>
00326   #include <data_struct/string_hash.cpp>
00327   #include <data_struct/string_hasher.cpp>
00328   #include <data_struct/string_table.cpp>
00329   #include <data_struct/symbol_table.cpp>
00330   #include <data_struct/table_configurator.cpp>
00331   #include <loggers/console_logger.cpp>
00332   #include <loggers/file_logger.cpp>
00333   #include <loggers/locked_logger.cpp>
00334   #include <loggers/null_logger.cpp>
00335   #include <loggers/program_wide_logger.cpp>
00336   #include <nodes/node.cpp>
00337   #include <nodes/path.cpp>
00338   #include <nodes/symbol_tree.cpp>
00339   #include <nodes/tree.cpp>
00340   #include <opsystem/application_base.cpp>
00341   #include <opsystem/application_shell.cpp>
00342   #include <opsystem/byte_filer.cpp>
00343   #include <opsystem/command_line.cpp>
00344   #include <opsystem/critical_events.cpp>
00345   #include <opsystem/directory.cpp>
00346   #include <opsystem/filename.cpp>
00347   #include <opsystem/ini_config.cpp>
00348   #include <opsystem/ini_parser.cpp>
00349   #include <opsystem/path_configuration.cpp>
00350   #include <opsystem/rendezvous.cpp>
00351   #include <textual/byte_format.cpp>
00352   #include <textual/list_parsing.cpp>
00353   #include <textual/parser_bits.cpp>
00354   #include <textual/string_manipulation.cpp>
00355   #include <textual/tokenizer.cpp>
00356 #endif // __BUILD_STATIC_APPLICATION__
00357 

Generated on Fri Nov 28 04:28:49 2008 for HOOPLE Libraries by  doxygen 1.5.1