Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/syn/link.cc
    1| // Synopsis C++ Parser: link.cc source file
    2| // Implements the link module/program that reads the stored syntax
    3| // highlighting info and original file, and generates the output HTML file.
    4| 
    5| // $Id: link.cc,v 1.25 2002/12/09 13:53:50 chalky Exp $
    6| //
    7| // This file is a part of Synopsis.
    8| // Copyright (C) 2001, 2002 Stephen Davies
    9| // Copyright (C) 2002 Stefan Seefeld
   10| //
   11| // Synopsis is free software; you can redistribute it and/or modify it
   12| // under the terms of the GNU General Public License as published by
   13| // the Free Software Foundation; either version 2 of the License, or
   14| // (at your option) any later version.
   15| //
   16| // This program is distributed in the hope that it will be useful,
   17| // but WITHOUT ANY WARRANTY; without even the implied warranty of
   18| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   19| // General Public License for more details.
   20| //
   21| // You should have received a copy of the GNU General Public License
   22| // along with this program; if not, write to the Free Software
   23| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   24| // 02111-1307, USA.
   25| 
   26| // $Log: link.cc,v $
   27| // Revision 1.25  2002/12/09 13:53:50  chalky
   28| // Fixed to not use the PyString's internal data for the toc list
   29| //
   30| // Revision 1.24  2002/11/17 12:11:43  chalky
   31| // Reformatted all files with astyle --style=ansi, renamed fakegc.hh
   32| //
   33| // Revision 1.23  2002/11/01 08:15:31  chalky
   34| // Remove debug cout
   35| //
   36| // Revision 1.22  2002/11/01 07:15:56  chalky
   37| // Reject duplicate links
   38| //
   39| // Revision 1.21  2002/11/01 04:04:29  chalky
   40| // Clean up HTML: no empty spans, decode &2c; in URL, to-EOL comments.
   41| //
   42| // Revision 1.20  2002/10/28 18:03:54  chalky
   43| // Properly decode scoped names, and avoid crash if not using links_scope
   44| //
   45| // Revision 1.19  2002/10/28 17:38:17  chalky
   46| // Ooops, get rid of #
   47| //
   48| // Revision 1.18  2002/10/28 17:29:09  chalky
   49| // Add anchor link with line number to each line
   50| //
   51| // Revision 1.17  2002/10/25 08:56:56  chalky
   52| // Prevent bad output by clipping to end of line
   53| //
   54| // Revision 1.16  2002/10/11 11:09:12  chalky
   55| // Remove debugging perror statement
   56| 
   57| /*
   58|  * This is the 'link' program, that reads a .links file and the original file,
   59|  * and outputs a file with the links interspersed as HTML. It is designed such
   60|  * that this output be placed inside another HTML file, and as such has no
   61|  * other HTML except the actual output and the links.
   62|  */
   63| 
   64| #include <iostream>
   65| #include <fstream>
   66| #include <iterator>
   67| #include <vector>
   68| #include <set>
   69| #include <map>
   70| #include <string>
   71| #include <limits.h>
   72| 
   73| #include <stdio.h>
   74| 
   75| //. Static namespace for link module
   76| namespace
   77| {
   78| //. Encapsulation of a link fragment. Links can be of several types, such
   79| //. as start, end, or some other formatting type. They are split into
   80| //. start and end so that spans can be nested properly
   81| struct Link
   82| {
   83|     //. A scoped name type
   84|     typedef std::vector<std::stringName;
   85|     //. The line and column of the link
   86|     int linecol;
   87|     //. Enumeration of the type of link. These should be in order of
   88|     //. priority, so nested types should be nested in this list:
   89|     //. <a><b>foo</b></a> means enum ordering: A_START,B_START,B_END,A_END
   90|     enum Type
   91|     {
   92|         LINK_START//.< Start of a label link
   93|         REF_START//.< Start of reference link
   94|         SPAN_START,
   95|         SPAN_END,
   96|         REF_END,
   97|         LINK_END //.< End of a link
   98|     };
   99|     //. The type of this link
  100|     Type type;
  101|     //. The scoped name of this link
  102|     Name name;
  103|     //. The description of this link
  104|     std::string desc;
  105| 
  106|     //. Less-than functor that compares column and type
  107|     struct lt_col
  108|     {
  109|         bool operator() (const Link* a, const Link* b) const
  110|         {
  111|             if (a->col != b->col)
  112|                 return a->col < b->col;
  113|             return a->type < b->type;
  114|         }
  115|     };
  116|     //. Set of links sorted by column
  117|     typedef std::set
  118|         <Link*, lt_col> Line;
  119|     //. Map of Lines keyed by line number
  120|     typedef std::map<int, Line> Map;
  121|     //. Write link to the output stream for debugging
  122|     std::ostreamwrite(std::ostream& o);
  123| };
  124| 
  125| //. Debugging output operator for members of the Link Map
  126| std::ostreamoperator<<(std::ostream& o, const Link::Map::value_type& linepair)
  127| {
  128|     const Link::Lineline = linepair.second;
  129|     o << "Line " << (*line.begin())->line << "\n";
  130|     Link::Line::const_iterator iter = line.begin();
  131|     while (iter != line.end())
  132|         (*iter++)->write(o) << "\n";
  133|     return o;
  134| }
  135| 
  136| //. Debugging output method for Links
  137| std::ostreamLink::write(std::ostream& o)
  138| {
  139|     o << " " << col << " (" << type << ") ";
  140|     Link::Name::const_iterator iter = name.begin();
  141|     if (iter == name.end())
  142|     {
  143|         o << "<no name>";
  144|         return o;
  145|     }
  146|     o << *iter++;
  147|     while (iter != name.end())
  148|         o << "::" << *iter++;
  149|     return o;
  150| }
  151| //. Filename of the input source file
  152| const charinput_filename = 0;
  153| //. Filename of the output HTML file
  154| const charoutput_filename = 0;
  155| //. Filename of the links file
  156| const charlinks_filename = 0;
  157| //. Scope to prepend to links before to find in TOC
  158| const charlinks_scope = 0;
  159| //. A list of TOC's to load
  160| std::vector<std::stringtoc_filenames;
  161| //. True if should append to output file. Note that this only works if the
  162| //. process previously using the file has flushed things to disk!
  163| bool links_append = false;
  164| //. A map of links to insert into the output
  165| Link::Map links;
  166| 
  167| //. Type of the TableOfContents
  168| typedef std::map<std::string, std::string> TOC;
  169| //. The TOC used for looking up hrefs
  170| TOC toc;
  171| 
  172| 
  173| //. Parses the command line arguments given to main()
  174| void parse_args(int argc, char** argv)
  175| {
  176|     for (int i = 1i < argci++)
  177|     {
  178|         if (!strcmp(argv[i], "-i"))
  179|         {
  180|             if (++i >= argc)
  181|             {
  182|                 std::cerr << "-i needs argument" << std::endl;
  183|                 exit(1);
  184|             }
  185|             input_filename = argv[i];
  186|         }
  187|         else if (!strcmp(argv[i], "-o"))
  188|         {
  189|             if (++i >= argc)
  190|             {
  191|                 std::cerr << "-o needs argument" << std::endl;
  192|                 exit(1);
  193|             }
  194|             output_filename = argv[i];
  195|         }
  196|         else if (!strcmp(argv[i], "-l"))
  197|         {
  198|             if (++i >= argc)
  199|             {
  200|                 std::cerr << "-l needs argument" << std::endl;
  201|                 exit(1);
  202|             }
  203|             links_filename = argv[i];
  204|         }
  205|         else if (!strcmp(argv[i], "-a"))
  206|             links_append = true;
  207|         else if (!strcmp(argv[i], "-t"))
  208|         {
  209|             if (++i >= argc)
  210|             {
  211|                 std::cerr << "-t needs argument" << std::endl;
  212|                 exit(1);
  213|             }
  214|             toc_filenames.push_back(argv[i]);
  215|         }
  216|         else
  217|         {
  218|             std::cerr << "Unknown option: " << argv[i] << std::endl;
  219|             exit(1);
  220|         }
  221|     }
  222|     if (!input_filename || !output_filename || !links_filename)
  223|     {
  224|         std::cerr << "Usage:\n";
  225|         std::cerr << " link -i input.cc -o output.html -l links.file [ -a ]\n";
  226|         std::cerr << " -i   in\n -o   out\n -l   links\n -a   append to out\n";
  227|         std::cerr << std::endl;
  228|         exit(1);
  229|     }
  230| }
  231| 
  232| //. Writes some text to the output. It replaces chars that might be
  233| //. confused by HTML, such as < and >. All spaces are replaced with
  234| //. non-breaking spaces, and tabs are expanded to 8-col tabstops (hence the
  235| //. col argument)
  236| void write(std::ostream& out, int col, char* buf, int len, int buflen)
  237| {
  238|     charptr = buf, *end = buf+len;
  239|     while (ptr != end && col < buflen)
  240|     {
  241|         char c = *ptr++;
  242|         switch (c)
  243|         {
  244|         case '<':
  245|             out << "&lt;";
  246|             break;
  247|         case '>':
  248|             out << "&gt;";
  249|             break;
  250|         case ' ':
  251|             out << "&nbsp;";
  252|             break;
  253|         case '"':
  254|             out << "&quot;";
  255|             break;
  256|         case '&':
  257|             out << "&amp;";
  258|             break;
  259|         case '\t':
  260|             {
  261|                 int next = ((col/8)+1)*8;
  262|                 while (col++ < next)
  263|                     out << "&nbsp;";
  264|                 continue;
  265|             }
  266|         default:
  267|             out << c;
  268|         }
  269|         col++;
  270|     }
  271| }
  272| 
  273| //. Writes the line number to the output
  274| void write_lineno(std::ostream& out, int line)
  275| {
  276|     // out << setw(4) << line << "| "; <-- but with& nbsp;'s
  277|     out << "<a name=\"" << line << "\"></a>";
  278|     out << "<span class=\"file-linenum\">";
  279|     int mag = 10000;
  280|     while (mag > 1)
  281|     {
  282|         int digit = line / mag;
  283|         if (digit)
  284|             break;
  285|         out << "&nbsp;";
  286|         mag /= 10;
  287|     }
  288|     out << line << "|&nbsp;";
  289|     out << "</span>";
  290| }
  291| 
  292| //. Undoes the %FF encoding
  293| std::string decode(const std::string& str)
  294| {
  295|     std::string ret;
  296|     std::string::const_iterator iter = str.begin(), end = str.end();
  297|     while (iter != end)
  298|     {
  299|         char abc = *iter++;
  300|         if (c == '%')
  301|         {
  302|             a = *iter++;
  303|             b = *iter++;
  304|             if (a >= 'a')
  305|                 a -= 'a' - 10;
  306|             else if (a >= 'A')
  307|                 a -= 'A' - 10;
  308|             else
  309|                 a -= '0';
  310|             if (b >= 'a')
  311|                 b -= 'a' - 10;
  312|             else if (b >= 'A')
  313|                 b -= 'A' - 10;
  314|             else
  315|                 b -= '0';
  316|             c = a * 16 + b;
  317|         }
  318|         ret.push_back(c);
  319|     }
  320|     return ret;
  321| }
  322| 
  323| //. Writes whatever indent there is in the buf to the output using the
  324| //. special span. 'col' is modified to the first non-indent character.
  325| void write_indent(std::ostream& out, char* buf, int& col, int buflen)
  326| {
  327|     int len = 0;
  328|     charptr = buf;
  329|     while (*ptr && (*ptr == ' ' || *ptr == '\t'))
  330|         ptr++, len++;
  331|     if (!len)
  332|         return;
  333|     out << "<span class=\"file-indent\">";
  334|     write(outcolbuflenbuflen);
  335|     out << "</span>";
  336|     col += len;
  337| }
  338| 
  339| //. Returns true if the link is a duplicate.
  340| bool is_duplicate(Link* link, int len)
  341| {
  342|     Link::Lineline = links[link->line];
  343|     Link::Line::iterator iter = line.find(link);
  344|     if (iter == line.end())
  345|         return false;
  346| 
  347|     // iter matches by col, but try to find match by name
  348|     while ((*iter)->name != link->name)
  349|     {
  350|         ++iter;
  351|         if (iter == line.end() || (*iter)->col != link->col)
  352|             // Couldn't match by name for this column
  353|             return false;
  354|     }
  355| 
  356|     // Matched start by name.. try and find end too
  357|     link->col += len;
  358|     iter = line.find(link);
  359|     if (iter == line.end())
  360|         return false;
  361| 
  362|     // iter matches by col, but try to find match by name
  363|     while ((*iter)->name != link->name)
  364|     {
  365|         ++iter;
  366|         if (iter == line.end() || (*iter)->col != link->col)
  367|             // Couldn't match by name for this column
  368|             return false;
  369|     }
  370|     // name matched at both ends
  371|     return true;
  372| }
  373| 
  374| //. Reads the links file into the 'links' map.
  375| void read_links() throw (std::string)
  376| {
  377|     std::ifstream in(links_filename);
  378|     char buf[4096];
  379|     if (!in)
  380|     {
  381|         return;
  382|     // this is okay -- just means the file wont be linked
  383|     std::string wordtype;
  384|     int linelen;
  385|     while (in)
  386|     {
  387|         if (!(in >> line))
  388|             break;
  389|         Linklink = new Link;
  390|         link->line = line;
  391|         in >> link->col >> len >> type;
  392|         link->col--; // we count at zero, file counts at one
  393|         if (len == -1)
  394|             len = INT_MAX/2; // div 2 to prevent wrap-around
  395|         if (type != "SPAN")
  396|         {
  397|             if (type == "DEF")
  398|                 link->type = Link::LINK_START;
  399|             else if (type == "REF")
  400|                 link->type = Link::REF_START;
  401|             else if (type == "CALL")
  402|                 link->type = Link::REF_START;
  403|             else if (type == "IMPL")
  404|                 link->type = Link::REF_START;
  405|             else if (type == "UDIR")
  406|                 link->type = Link::REF_START;
  407|             else
  408|                 link->type = Link::REF_START;
  409|             int c = -1;
  410|             // Use up field sep ' '
  411|             in.get();
  412|             // Loop over scoped name till next ' '
  413|             do
  414|             {
  415|                 in >> word;
  416|                 // Replace '160's with spaces
  417|                 //for (std::string::size_type pos = word.find(160); pos != std::string::npos; pos = word.find(160, pos)) {
  418|                 //    word[pos] = ' ';
  419|                 //}
  420|                 word = decode(word);
  421|                 size_t start = 0end;
  422|                 while ((end = word.find('\t'start)) != std::string::npos)
  423|                 {
  424|                     link->name.push_back(word.substr(startend-start));
  425|                     start = end + 1;
  426|                 }
  427|                 link->name.push_back(word.substr(startend-start));
  428|             }
  429|             while (in && (c = in.get()) != '\n' && c != ' ');
  430|             // Read description
  431|             if (!in.getline(buf4096))
  432|                 break;
  433|             link->desc = decode(buf);
  434|         }
  435|         else
  436|         {
  437|             link->type = Link::SPAN_START;
  438|             in >> type;
  439|             link->name.push_back(decode(type));
  440|         }
  441|         // Skip to next line if duplicate link
  442|         if (is_duplicate(linklen))
  443|             continue;
  444|         links[line].insert(link);
  445|         // Add link end
  446|         Linkend = new Link;
  447|         end->line = line;
  448|         end->col = link->col + len;
  449|         switch (link->type)
  450|         {
  451|         case Link::LINK_START:
  452|             end->type = Link::LINK_END;
  453|             break;
  454|         case Link::REF_START:
  455|             end->type = Link::REF_END;
  456|             break;
  457|         case Link::SPAN_START:
  458|             end->type = Link::SPAN_END;
  459|             break;
  460|         default:
  461|             // throw some error
  462|         }
  463|         links[line].insert(end);
  464|     }
  465| }
  466| 
  467| //. Debugging method to dump all links to cout.
  468| void dump_links()
  469| {
  470|     std::copy(links.begin(), links.end(), std::ostream_iterator<Link::Map::value_type>(std::cout"\n"));
  471| }
  472| 
  473| //. Reads in the TOC files. The filenames are taken from the toc_filenames
  474| //. array and store in the 'toc' map.
  475| void read_tocs() throw (std::string)
  476| {
  477|     char buf[3][4096];
  478|     int url_len = 0;
  479|     std::vector<std::string>::iterator iter = toc_filenames.begin();
  480|     while (iter != toc_filenames.end())
  481|     {
  482|         std::string toc_filename = *iter++;
  483|         size_t pipe = toc_filename.find('|');
  484|         if (pipe != std::string::npos)
  485|         {
  486|             strcpy(buf[2], toc_filename.c_str() + pipe + 1);
  487|             url_len = toc_filename.size() - pipe - 1;
  488|             toc_filename = toc_filename.substr(0pipe);
  489|         }
  490|         std::ifstream in(toc_filename.c_str());
  491|         if (!in)
  492|         {
  493|             throw std::string("Error opening toc file: ")+toc_filename;
  494|         }
  495|         while (in)
  496|         {
  497|             // Get line
  498|             if (!in.getline(buf[0], 4096','))
  499|                 break;
  500|             if (!in.getline(buf[1], 4096','))
  501|                 break;
  502|             if (!in.getline(buf[2]+url_len4096-url_len))
  503|                 break;
  504|             // convert& 2c;'s to commas
  505|             for (char*s = buf[0]; *ss++)
  506|             {
  507|                 if (!strncmp(s"&amp;"5))
  508|                 {
  509|                     *s = '&';
  510|                     memmove(s+1s+5strlen(s+5)+1);
  511|                 }
  512|                 if (!strncmp(s"&2c;"4))
  513|                 {
  514|                     *s = ',';
  515|                     memmove(s+1s+4strlen(s+4)+1);
  516|                 }
  517|             }
  518|             for (char*s = buf[2]+url_len; *ss++)
  519|             {
  520|                 if (!strncmp(s"&amp;"5))
  521|                 {
  522|                     *s = '&';
  523|                     memmove(s+1s+5strlen(s+5)+1);
  524|                 }
  525|                 if (!strncmp(s"&2c;"4))
  526|                 {
  527|                     *s = ',';
  528|                     memmove(s+1s+4strlen(s+4)+1);
  529|                 }
  530|             }
  531|             // We cheat here and exclude lines that dont have
  532|             // 'links_scope' at the start, and then chop it from the ones
  533|             // that do
  534|             if (links_scope)
  535|             {
  536|                 if (strncmp(buf[0], links_scopestrlen(links_scope)))
  537|                     continue;
  538|                 memmove(buf[0], buf[0] + strlen(links_scope), strlen(buf[0]) - strlen(links_scope) + 1);
  539|             }
  540|             // Store in toc map
  541|             toc[buf[0]] = buf[2];
  542|         }
  543|     }
  544| }
  545| 
  546| //. Reads the input file, inserts links, and writes the result to the
  547| //. output. It uses the 'links' line map to iterate through the file
  548| //. sequentially.
  549| void link_file() throw (std::string)
  550| {
  551|     std::ifstream in(input_filename);
  552|     if (!in)
  553|     {
  554|         throw std::string("Error opening input file: ")+input_filename;
  555|     }
  556|     std::ofstream out(output_filename, links_append ? std::ios::app : std::ios::out);
  557|     if (!out)
  558|     {
  559|         throw std::string("Error opening output file: ")+output_filename;
  560|     }
  561|     char buf[4096];
  562|     int line = 1buflen;
  563|     Link::Map::iterator iter = links.begin(), end = links.end();
  564|     while (in)
  565|     {
  566|         // Get line
  567|         if (!in.getline(buf4096))
  568|             break;
  569|         buflen = strlen(buf);
  570|         write_lineno(outline);
  571|         // Get Link::Line
  572|         while (iter != end && iter->first < line)
  573|             ++iter;
  574|         if (iter != end && iter->first == line)
  575|         {
  576|             // Insert links and write at same time
  577|             int col = 0;
  578|             write_indent(outbufcolbuflen);
  579|             out << "<span class=\"file-default\">";
  580|             Link::Lineline = iter->second;
  581|             Link::Line::iterator link_i = line.begin();
  582|             while (link_i != line.end())
  583|             {
  584|                 Linklink = *link_i++;
  585|                 if (col < link->col)
  586|                 {
  587|                     write(outcolbuf+collink->col - colbuflen);
  588|                     col = link->col;
  589|                 }
  590|                 switch (link->type)
  591|                 {
  592|                 case Link::LINK_START:
  593|                 case Link::REF_START:
  594|                     {
  595|                         std::string name;
  596|                         Link::Name::iterator name_iter = link->name.begin();
  597|                         if (name_iter != link->name.end())
  598|                             name = *name_iter++;
  599|                         while (name_iter != link->name.end())
  600|                             name += "::" + *name_iter++;
  601|                         TOC::iterator toc_iter = toc.find(name);
  602|                         if (toc_iter == toc.end())
  603|                         {
  604|                             if (link->type == Link::LINK_START)
  605|                                 out << "<a name=\"" << name;
  606|                             else
  607|                                 out << "<a href=\"#" << name;
  608|                         }
  609|                         else
  610|                         {
  611|                             std::string href = toc_iter->second;
  612|                             if (link->type == Link::LINK_START)
  613|                                 out << "<a class=\"file-def\" name=\""<<name<<"\"";
  614|                             else
  615|                                 out << "<a class=\"file-ref\"";
  616|                             out << " href=\"" << href;
  617|                         }
  618|                         out << "\" title=\"" << link->desc << "\">";
  619|                         break;
  620|                     }
  621|                 case Link::REF_END:
  622|                 case Link::LINK_END:
  623|                     out << "</a>";
  624|                     break;
  625|                 case Link::SPAN_START:
  626|                     out << "<span class=\"" << link->name[0] << "\">";
  627|                     break;
  628|                 case Link::SPAN_END:
  629|                     out << "</span>";
  630|                     break;
  631|                 }
  632|             }
  633|             // Write any left-over buffer
  634|             write(outcolbuf+col, -1buflen);
  635|             out << "</span>";
  636|         }
  637|         else
  638|         {
  639|             // Write buf
  640|             int col = 0;
  641|             write_indent(outbufcolbuflen);
  642|             if (col < buflen)
  643|             {
  644|                 out << "<span class=\"file-default\">";
  645|                 write(outcolbuf+col, -1buflen);
  646|                 out << "</span>";
  647|             }
  648|         }
  649|         out << "<br>\n";
  650|         line++;
  651|     }
  652| }
  653| }
  654| // namespace {anon}
  655| 
  656| //. Clear all global vars
  657| void reset()
  658| {
  659|     links.clear();
  660|     toc.clear();
  661|     toc_filenames.clear();
  662| }
  663| 
  664| #ifdef STANDALONE
  665| 
  666| //. Method for a stand-alone 'link-synopsis' program
  667| int main(int argc, char** argv)
  668| {
  669|     parse_args(argc, argv);
  670| 
  671|     try
  672|     {
  673|         read_links();
  674| 
  675|         read_tocs();
  676| 
  677|         link_file();
  678|     }
  679|     catch (std::string err)
  680|     {
  681|         std::cerr << "Error: " << err << std::endl;
  682|         return 1;
  683|     }
  684| 
  685|     return 0;
  686| }
  687| 
  688| #else
  689| 
  690| #include PYTHON_INCLUDE
  691| 
  692| extern "C"
  693| {
  694|     static PyObject* linkError;
  695| 
  696|     //. The main python method, equivalent to the main() function
  697|     static PyObjectpy_link(PyObject* self, PyObject* args)
  698|     {
  699|         PyObject *py_tocs, *py_file;
  700| 
  701|         if (!PyArg_ParseTuple(
  702|                     args"Ossss",
  703|                     &py_tocs,& input_filename,& output_filename,& links_filename,& links_scope
  704|                 ))
  705|             return NULL;
  706| 
  707|         // Extract TOC array
  708|         int toc_size = PyList_Size(py_tocs);
  709|         for (int i = 0i < toc_sizei++)
  710|         {
  711|             if (!(py_file = PyList_GetItem(py_tocsi)))
  712|                 return NULL;
  713|             charfilename = PyString_AsString(py_file);
  714|             if (!filename)
  715|                 return NULL;
  716|             toc_filenames.push_back(filename);
  717|         }
  718|         // Extract filenames
  719|         if (!(input_filename))
  720|             return NULL;
  721|         if (!(output_filename))
  722|             return NULL;
  723|         if (!(links_filename))
  724|             return NULL;
  725|         if (!(links_scope))
  726|             return NULL;
  727|         // Do stuff
  728|         try
  729|         {
  730|             read_links();
  731|             read_tocs();
  732|             link_file();
  733|             reset();
  734|         }
  735|         catch (const std::string& err)
  736|         {
  737|             std::cerr << "Error: " << err << std::endl;
  738|             PyErr_SetString(linkErrorerr.c_str());
  739|             reset();
  740|             return NULL;
  741|         }
  742| 
  743|         Py_INCREF(Py_None);
  744|         return Py_None;
  745|     }
  746| 
  747|     //. The list of methods in this python module
  748|     static PyMethodDef link_methods[] =
  749|         {
  750|             {(char*)"link", py_link, METH_VARARGS},
  751|             {NULL, NULL}
  752|         };
  753| 
  754|     //. The initialisation method for this module
  755|     void initlink()
  756|     {
  757|         PyObjectm = Py_InitModule((char*)"link", link_methods);
  758|         PyObject_SetAttrString(m, (char*)"version"PyString_FromString("0.1"));
  759| 
  760|         // Add an exception called "error" to the module
  761|         PyObjectd = PyModule_GetDict(m);
  762|         linkError = PyErr_NewException("link.error", NULL, NULL);
  763|         PyDict_SetItemString(d"error"linkError);
  764|     }
  765| 
  766| };
  767| 
  768| 
  769| #endif
  770| // vim: set ts=8 sts=4 sw=4 et: