-/************************************************************************
- ************************************************************************
- FAUST compiler
- Copyright (C) 2009 GRAME, Centre National de Creation Musicale
- ---------------------------------------------------------------------
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ************************************************************************
- ************************************************************************/
-
-
-
-/*****************************************************************************
- ******************************************************************************
-
-
- The Documentator Language
-
-
- ******************************************************************************
- *****************************************************************************/
-
-
-/**
- * @file doc.cpp
- * @author Karim Barkati and Yann Orlarey
- * @version 1.0
- * @date 2009
- * @brief Implementation of documentation trees support and printing.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <algorithm>
-#include <functional>
-
-#include <iostream>
-#include <fstream>
-#include <sstream>
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "ppbox.hh"
-#include "prim2.hh"
-#include "doc.hh"
-#include "eval.hh"
-#include "errormsg.hh"
-#include "doc_Text.hh"
-#include "sigprint.hh"
-#include "propagate.hh"
-#include "enrobage.hh"
-#include "drawschema.hh"
-#include "names.hh"
-#include "simplify.hh"
-#include "privatise.hh"
-#include "recursivness.hh"
-#include "sourcereader.hh"
-#include "lateq.hh"
-#include "doc_compile.hh"
-#include "doc_lang.hh"
-#include "doc_notice.hh"
-#include "doc_autodoc.hh"
-#include "compatibility.hh"
-
-
-
-#define MAXIDCHARS 5 ///< max numbers (characters) to represent ids (e.g. for directories).
-
-using namespace std ;
-
-
-/*****************************************************************************
- Globals and prototyping
- *****************************************************************************/
-
-extern Tree gExpandedDefList;
-extern map<Tree, set<Tree> > gMetaDataSet;
-extern map<string, string> gDocMetadatasStringMap;
-extern map<string, string> gDocMathStringMap;
-extern bool gDetailsSwitch;
-extern bool gStripDocSwitch;
-extern string gFaustDirectory;
-extern string gFaustSuperDirectory;
-extern string gFaustSuperSuperDirectory;
-extern string gMasterDocument;
-extern string gMasterName;
-extern SourceReader gReader;
-
-extern string gDocName; ///< Contains the filename for out documentation.
-static const char* gDocDevSuffix; ///< ".tex" (or .??? - used to choose output device).
-static string gCurrentDir; ///< Room to save current directory name.
-static const string gLatexheaderfilename = "latexheader.tex";
-
-vector<Tree> gDocVector; ///< Contains <mdoc> parsed trees: DOCTXT, DOCEQN, DOCDGM.
-
-static struct tm gCompilationDate;
-
-bool gLstDependenciesSwitch = true; ///< mdoc listing management.
-bool gLstMdocTagsSwitch = true; ///< mdoc listing management.
-bool gLstDistributedSwitch = true; ///< mdoc listing management.
-
-enum { langEN, langFR, langIT };
-string gDocLang;
-
-/* Printing functions */
-static void printlatexheader(istream& latexheader, const string& faustversion, ostream& docout);
-static void printfaustlistings(ostream& docout);
-static void printfaustlisting(string& path, ostream& docout);
-static void printlatexfooter(ostream& docout);
-static void printdoccontent(const char* svgTopDir, const vector<Tree>& docVector, const string& faustversion, ostream& docout);
-static void printfaustdocstamp(const string& faustversion, ostream& docout);
-static void printDocEqn(Lateq* ltq, ostream& docout);
-static void printDocDgm(const Tree expr, const char* svgTopDir, ostream& docout, int i);
-static void printDocMetadata(const Tree expr, ostream& docout);
-
-/* Primary sub-functions for <equation> handling */
-static void prepareDocEqns( const vector<Tree>& docBoxes, vector<Lateq*>& docCompiledEqnsVector ); ///< Caller function.
-static void collectDocEqns( const vector<Tree>& docBoxes, vector<Tree>& eqBoxes ); ///< step 0. Feed a vector.
-static void mapEvalDocEqn( const vector<Tree>& eqBoxes, const Tree& env, vector<Tree>& evalEqBoxes ); ///< step 1. Evaluate boxes.
-static void mapGetEqName( const vector<Tree>& evalEqBoxes, vector<string>& eqNames ); ///< step 2. Get boxes name.
-static void calcEqnsNicknames( const vector<string>& eqNames, vector<string>& eqNicknames ); ///< step 3. Calculate nicknames.
-static void mapPrepareEqSig( const vector<Tree>& evalEqBoxes, vector<int>& eqInputs, vector<int>& eqOutputs, vector<Tree>& eqSigs ); ///< step 4&5. Propagate and prepare signals.
-static void mapSetSigNickname( const vector<string>& eqNicknames, const vector<int>& eqInputs, const vector<Tree>& eqSigs ); ///< step 6. Set signals nicknames.
-static void collectEqSigs( const vector<Tree>& eqSigs, Tree& superEqList ); ///< step 7. Collect all signals in a superlist.
-static void annotateSuperList( DocCompiler* DC, Tree superEqList ); ///< step 8. Annotate superlist.
-//static void calcAndSetLtqNames( Tree superEqList ); ///< step 9.
-static void mapCompileDocEqnSigs( const vector<Tree>& eqSigs, const vector<int>& eqInputs, const vector<int>& eqOutputs, DocCompiler* DC, vector<Lateq*>& docCompiledEqnsVector ); ///< step 10. Compile equations.
-
-/* Secondary sub-functions for <equation> handling */
-static string calcNumberedName(const char* base, int i);
-static void getBoxInputsAndOutputs(const Tree t, int& numInputs, int& numOutputs);
-static string calcDocEqnInitial(const string s);
-
-/* Notice related functions */
-static void initCompilationDate();
-static struct tm* getCompilationDate();
-
-/* Files functions */
-static int cholddir ();
-static int mkchdir(const char* dirname);
-static int makedir(const char* dirname);
-static void getCurrentDir();
-static istream* openArchFile (const string& filename);
-static char* legalFileName(const Tree t, int n, char* dst);
-static string rmExternalDoubleQuotes(const string& s);
-static void copyFaustSources(const char* projname, const vector<string>& pathnames);
-vector<string>& docCodeSlicer(const string& faustfile, vector<string>& codeSlices);
-static void printdocCodeSlices(const string& code, ostream& docout);
-static bool doesFileBeginWithCode(const string& faustfile);
-
-//static void declareAutoDoc();
-
-
-
-/*****************************************************************************
- Types of Documentation Elements
- *****************************************************************************/
-
-Sym DOCTXT = symbol ("DocTxt");
-Tree docTxt(const char* name) { return tree( DOCTXT, tree(symbol(name)) ); }
-bool isDocTxt(Tree t) { return t->node() == Node(DOCTXT); }
-bool isDocTxt(Tree t0, const char** str)
-{
- Tree t1; Sym s;
- if ( isTree(t0, DOCTXT, t1) && isSym(t1->node(), &s) ) {
- *str = name(s);
- return true;
- } else {
- return false;
- }
-}
-
-Sym DOCEQN = symbol ("DocEqn");
-Tree docEqn(Tree x) { return tree(DOCEQN, x); }
-bool isDocEqn(Tree t, Tree& x) { return isTree(t, DOCEQN, x); }
-
-Sym DOCDGM = symbol ("DocDgm");
-Tree docDgm(Tree x) { return tree(DOCDGM, x); }
-bool isDocDgm(Tree t, Tree& x) { return isTree(t, DOCDGM, x); }
-
-Sym DOCNTC = symbol ("DocNtc");
-Tree docNtc() { return tree(DOCNTC); }
-bool isDocNtc(Tree t) { return isTree(t, DOCNTC); }
-
-Sym DOCLST = symbol ("DocLst");
-Tree docLst() { return tree(DOCLST); }
-bool isDocLst(Tree t) { return isTree(t, DOCLST); }
-
-Sym DOCMTD = symbol ("DocMtd");
-Tree docMtd(Tree x) { return tree(DOCMTD, x); }
-bool isDocMtd(Tree t, Tree& x) { return isTree(t, DOCMTD, x); }
-
-//string getDocTxt(Tree t) { return hd(t)->branch(0); }
-
-
-
-/*****************************************************************************
- Main Printing Function for the Documentation
- *****************************************************************************/
-
-
-/**
- * @brief The entry point to generate faust doc files.
- *
- * The entry point to generate the output LaTeX file, stored in the directory "<projname>-math/".
- * This file eventually references images for diagrams, generated in SVG subdirectories.
- * The device system was adapted from drawSchema's device system.
- *
- * @param[in] projname Basename of the new doc directory ("*-math").
- * @param[in] docdev The doc device; only ".tex" is supported for the moment.
- * @param[in] faustversion The current version of this Faust compiler.
- */
-void printDoc(const char* projname, const char* docdev, const char* faustversion)
-{
- gDocDevSuffix = docdev;
-
- /** File stuff : create doc directories and a tex file. */
- //cerr << "Documentator : printDoc : gFaustDirectory = '" << gFaustDirectory << "'" << endl;
- //cerr << "Documentator : printDoc : gFaustSuperDirectory = '" << gFaustSuperDirectory << "'" << endl;
- //cerr << "Documentator : printDoc : gFaustSuperSuperDirectory = '" << gFaustSuperSuperDirectory << "'" << endl;
- //cerr << "Documentator : printDoc : gCurrentDir = '" << gCurrentDir << "'" << endl;
-
- makedir(projname); // create a top directory to store files
-
- string svgTopDir = subst("$0/svg", projname);
- makedir(svgTopDir.c_str()); // create a directory to store svg-* subdirectories.
-
- string cppdir = subst("$0/cpp", projname);
- makedir(cppdir.c_str()); // create a cpp directory.
-
- string pdfdir = subst("$0/pdf", projname);
- makedir(pdfdir.c_str()); // create a pdf directory.
-
- /* Copy all Faust source files into an 'src' sub-directory. */
- vector<string> pathnames = gReader.listSrcFiles();
- copyFaustSources(projname, pathnames);
-
- string texdir = subst("$0/tex", projname);
- mkchdir(texdir.c_str()); // create a directory and move into.
-
- /** Create THE mathdoc tex file. */
- ofstream docout(subst("$0.$1", gDocName, docdev).c_str());
- cholddir(); // return to current directory
-
- /** Init and load translation file. */
- loadTranslationFile(gDocLang);
-
- /** Simulate a default doc if no <mdoc> tag detected. */
- if (gDocVector.empty()) { declareAutoDoc(); }
-
- /** Printing stuff : in the '.tex' ouptut file, eventually including SVG files. */
- printfaustdocstamp(faustversion, docout); ///< Faust version and compilation date (comment).
- istream* latexheader = openArchFile(gLatexheaderfilename);
- printlatexheader(*latexheader, faustversion, docout); ///< Static LaTeX header (packages and setup).
- printdoccontent(svgTopDir.c_str(), gDocVector, faustversion, docout); ///< Generate math contents (main stuff!).
- printlatexfooter(docout); ///< Static LaTeX footer.
-}
-
-
-
-/*****************************************************************************
- LaTeX basic printing functions of the Documentation
- *****************************************************************************/
-
-/**
- * Print a static LaTeX header.
- *
- * @param[in] latexheader The file containing the static part of the LaTeX header.
- * @param[in] faustversion The current version of this Faust compiler.
- * @param[out] docout The LaTeX output file to print into.
- */
-static void printlatexheader(istream& latexheader, const string& faustversion, ostream& docout)
-{
- string s;
- while(getline(latexheader, s)) docout << s << endl;
-
- /** Specific LaTeX macros for Faust */
- docout << "\\newcommand{\\faustfilename}{" << gMasterDocument << "}" << endl;
- docout << "\\newcommand{\\faustdocdir}{" << gMasterName << "-mdoc}" << endl;
- docout << "\\newcommand{\\faustprogname}{" << gMasterName << "}" << endl;
- docout << "\\newcommand{\\faustversion}{" << faustversion << "}" << endl;
- char datebuf [150];
- strftime (datebuf, 150, "%B %d, %Y", getCompilationDate());
- docout << "\\newcommand{\\faustdocdate}{" << datebuf << "}" << endl;
-
- docout << endl << "\\begin{document}" << endl;
-}
-
-
-/**
- * @Brief Print a metadata set.
- *
- * Each metadata is a set, in order to handle multiple items,
- * like multiple authors, even if most of metadatas have
- * unique items.
- *
- * @param[in] expr Parsed metadata keyname, as boxes tree.
- * @param[out] docout The output file to print into.
- */
-static void printDocMetadata(const Tree expr, ostream& docout)
-{
- if (gMetaDataSet.count(expr)) {
- string sep = "";
- set<Tree> mset = gMetaDataSet[expr];
-
- for (set<Tree>::iterator j = mset.begin(); j != mset.end(); j++) {
- docout << sep << rmExternalDoubleQuotes(tree2str(*j));
- sep = ", ";
- }
- }
-}
-
-
-/**
- * Print listings of each Faust code ".dsp" files,
- * calling the 'printfaustlisting' function.
- *
- * @param[out] docout The LaTeX output file to print into.
- */
-static void printfaustlistings(ostream& docout)
-{
- if (gLstDependenciesSwitch) {
- vector<string> pathnames = gReader.listSrcFiles();
- for (unsigned int i=0; i< pathnames.size(); i++) {
- printfaustlisting(pathnames[i], docout);
- }
- } else {
- printfaustlisting(gMasterDocument, docout);
- }
-}
-
-
-/**
- * Print a listing of the Faust code, in a LaTeX "listing" environment.
- * Strip content of <mdoc> tags.
- *
- * @param[in] faustfile The source file containing the Faust code.
- * @param[out] docout The LaTeX output file to print into.
- */
-static void printfaustlisting(string& faustfile, ostream& docout)
-{
- string s;
- ifstream src;
-
- //cerr << "Documentator : printfaustlisting : Opening file '" << faustfile << "'" << endl;
- src.open(faustfile.c_str(), ifstream::in);
-
- docout << endl << "\\bigskip\\bigskip" << endl;
- docout << "\\begin{lstlisting}[caption=\\texttt{" << filebasename(faustfile.c_str()) << "}]" << endl;
-
- bool isInsideDoc = false;
-
- if (faustfile != "" && src.good()) {
- while(getline(src, s)) { /** We suppose there's only one <mdoc> tag per line. */
- size_t foundopendoc = s.find("<mdoc>");
- if (foundopendoc != string::npos && gStripDocSwitch) isInsideDoc = true;
-
- if (isInsideDoc == false)
- docout << s << endl;
-
- size_t foundclosedoc = s.find("</mdoc>");
- if (foundclosedoc != string::npos && gStripDocSwitch) isInsideDoc = false;
- }
- } else {
- cerr << "ERROR : can't open faust source file " << faustfile << endl;
- exit(1);
- }
-
- docout << "\\end{lstlisting}" << endl << endl;
-}
-
-
-/**
- * Print the static LaTeX footer.
- *
- * @param[out] docout The LaTeX output file to print into.
- */
-static void printlatexfooter(ostream& docout)
-{
- docout << endl << "\\end{document}" << endl << endl;
-}
-
-
-/**
- * Print a "doc stamp" in the LaTeX document :
- * - the Faust version,
- * - the date of doc compilation,
- * - faust's web site URL.
- *
- * @param[in] faustversion The current version of this Faust compiler.
- * @param[out] docout The LaTeX output file to print into.
- */
-static void printfaustdocstamp(const string& faustversion, ostream& docout)
-{
- char datebuf [150];
- strftime (datebuf, 150, "%c", getCompilationDate());
-
- docout << "%% This documentation was generated with Faust version " << faustversion << endl;
- docout << "%% " << datebuf << endl;
- docout << "%% http://faust.grame.fr" << endl << endl;
-}
-
-
-
-/*****************************************************************************
- Main loop : launches prepare, evaluate, and print functions
- *****************************************************************************/
-
-/**
- * @brief Main documentator loop.
- *
- * First loop on gDocVector, which contains the faust <mdoc> trees.
- * Second loop for each of these <mdoc> trees, which contain parsed input expressions of 3 types :
- * DOCEQN for <equation> tags, DOCDGM for <diagram> tags, and DOCTXT for direct LaTeX text (no tag).
- * - DOCTXT expressions printing is trivial.
- * - DOCDGM expressions printing calls 'printDocDgm' to generate SVG files and print LaTeX "figure" code.
- * - DOCEQN expressions printing calls 'printDocEqn' after an important preparing work
- * has been done by 'prepareDocEqns'.
- *
- * @param[in] projname Basename of the new doc directory ("*-math").
- * @param[in] docVector Contains all <mdoc> parsed content (as boxes).
- * @param[in] faustversion The current version of this Faust compiler.
- * @param[out] docout The output file to print into.
- **/
-static void printdoccontent(const char* svgTopDir, const vector<Tree>& docVector, const string& faustversion, ostream& docout)
-{
- //cerr << endl << "Documentator : printdoccontent : " << docVector.size() << " <mdoc> tags read." << endl;
-
- /** Equations need to be prepared (named and compiled) before printing. */
- vector<Lateq*> docCompiledEqnsVector;
- prepareDocEqns( docVector, docCompiledEqnsVector ); ///< Quite a lot of stuff there.
- vector<Lateq*>::iterator eqn_it = docCompiledEqnsVector.begin();
-
- int dgmIndex = 1; ///< For diagram directories numbering.
-
- vector<string> docMasterCodeMap;
- docMasterCodeMap = docCodeSlicer(gMasterDocument, docMasterCodeMap);
-
- vector<Tree>::const_iterator doc;
- vector<string>::const_iterator code;
- code = docMasterCodeMap.begin();
-
- if(doesFileBeginWithCode(gMasterDocument) && (! docMasterCodeMap.empty()) && gLstDistributedSwitch ) {
- printdocCodeSlices(*code, docout);
- code++;
- }
-
- /** First level printing loop, on docVector. */
- for (doc=docVector.begin(); doc<docVector.end(); doc++, code++) {
-
- Tree L = reverse(*doc);
- //cerr << "Entering into <mdoc> parsing..." << endl;
-
- /** Second level printing loop, on each <mdoc>. */
- while (isList(L)) {
- Tree expr;
- if ( isDocEqn(hd(L), expr) ) { ///< After equations are well prepared and named.
- printDocEqn(*eqn_it++, docout);
- }
- else if ( isDocDgm(hd(L), expr) ) {
- printDocDgm(expr, svgTopDir, docout, dgmIndex++);
- }
- else if ( isDocMtd(hd(L), expr) ) {
- printDocMetadata(expr, docout);
- }
- else if ( isDocTxt(hd(L)) ) {
- docout << *hd(L)->branch(0); // Directly print registered doc text.
- }
- else if ( isDocNtc(hd(L)) ) {
- printDocNotice(faustversion, docout);
- }
- else if ( isDocLst(hd(L)) ) {
- printfaustlistings(docout);
- }
- else {
- cerr << "ERROR : " << *hd(L) << " is not a valid documentation type." << endl;
- }
- L = tl(L);
- }
- //cerr << " ...end of <mdoc> parsing." << endl;
-
- if ( code != docMasterCodeMap.end() && gLstDistributedSwitch ) {
- printdocCodeSlices(*code, docout);
- }
- }
-}
-
-
-
-/*****************************************************************************
- Primary sub-functions for <equation> handling
- *****************************************************************************/
-
-/**
- * @brief Caller function for all steps of doc equations preparation.
- *
- * Note : many of the functions called put their result into their last argument
- * in a "source / destination" manner,
- * the "destination" being declared before the function call.
- *
- * @param[in] docBoxes The <mdoc> boxes to collect and prepare.
- * @param[out] docCompiledEqnsVector The place to store compiled equations.
- */
-static void prepareDocEqns(const vector<Tree>& docBoxes, vector<Lateq*>& docCompiledEqnsVector)
-{
- vector<Tree> eqBoxes; collectDocEqns( docBoxes, eqBoxes ); ///< step 0. Feed a vector.
-
- if(! eqBoxes.empty() ) {
- vector<Tree> evalEqBoxes; mapEvalDocEqn( eqBoxes, gExpandedDefList, evalEqBoxes ); ///< step 1. Evaluate boxes.
- vector<string> eqNames; mapGetEqName( evalEqBoxes, eqNames ); ///< step 2. Get boxes name.
- vector<string> eqNicknames; calcEqnsNicknames( eqNames, eqNicknames ); ///< step 3. Calculate nicknames.
-
- vector<int> eqInputs;
- vector<int> eqOutputs;
- vector<Tree> eqSigs; mapPrepareEqSig( evalEqBoxes, eqInputs, eqOutputs, eqSigs ); ///< step 4&5. Propagate and prepare signals.
- mapSetSigNickname( eqNicknames, eqInputs, eqSigs ); ///< step 6. Set signals nicknames.
- Tree superEqList; collectEqSigs( eqSigs, superEqList ); ///< step 7. Collect all signals in a superlist.
-
- DocCompiler* DC = new DocCompiler(0, 0);
- annotateSuperList( DC, superEqList ); ///< step 8. Annotate superEqList.
- //calcAndSetLtqNames( superEqList ); ///< step 9. (directly in 10.)
- mapCompileDocEqnSigs( eqSigs, eqInputs, eqOutputs, DC, docCompiledEqnsVector ); ///< step 10. Compile every signal.
- }
-}
-
-
-/**
- * #0. Collect every <equation> found in all <mdoc> faust comments.
- *
- * @param[in] docBoxes The <mdoc> boxes to filter.
- * @param[out] eqBoxes The place to store only <equation> boxes.
- */
-static void collectDocEqns(const vector<Tree>& docBoxes, vector<Tree>& eqBoxes)
-{
- int nbdoceqn = 0;
-
- for (vector<Tree>::const_iterator doc=docBoxes.begin(); doc<docBoxes.end(); doc++) {
- Tree L = reverse(*doc);
- Tree expr;
- while (isList(L)) {
- if ( isDocEqn(hd(L), expr) ) {
- eqBoxes.push_back(expr);
- nbdoceqn++;
- }
- L = tl(L);
- }
- }
- //cerr << "Documentator : collectDocEqns : " << nbdoceqn << " <equation> tags found." << endl;
-}
-
-
-/**
- * #1. Evaluate every doc <equation> (evaluation replaces abstractions by symbolic boxes).
- *
- * @param[in] eqBoxes The boxes to evaluate.
- * @param[in] env The environment for the evaluation.
- * @param[out] evalEqBoxes The place to store evaluated equations boxes.
- */
-static void mapEvalDocEqn(const vector<Tree>& eqBoxes, const Tree& env, vector<Tree>& evalEqBoxes)
-{
- //cerr << "###\n# Documentator : mapEvalDocEqn" << endl;
-
- for ( vector<Tree>::const_iterator eq=eqBoxes.begin(); eq < eqBoxes.end(); eq++)
- {
- evalEqBoxes.push_back(evaldocexpr( *eq, env ));
- }
- //cerr << "Documentator : end of mapEvalDocEqn\n---" << endl;
-}
-
-
-/**
- * #2. Get name if exists, else create one, and store it.
- *
- * @param[in] evalEqBoxes Evaluated box trees, eventually containing an equation name.
- * @param[out] eqNames The place to store equations names.
- */
-static void mapGetEqName(const vector<Tree>& evalEqBoxes, vector<string>& eqNames)
-{
- //cerr << "###\n# Documentator : mapGetEqName" << endl;
-
- int i = 1;
- for( vector<Tree>::const_iterator eq = evalEqBoxes.begin(); eq < evalEqBoxes.end(); eq++, i++ ) {
- Tree id;
- string s;
- int n,m; getBoxType(*eq, &n, &m); // eq name only for bd without inputs
- if ( n==0 && getDefNameProperty(*eq, id) ) {
- s = tree2str(id);
- }
- else {
- s = calcNumberedName("doceqn-", i);
- }
- eqNames.push_back( s ) ;
- }
- //cerr << "Documentator : end of mapGetEqName\n---" << endl;
-}
-
-
-/**
- * #3. Calculate a nickname for each equation and store it.
- *
- * @param[in] eqNames Equations names to parse.
- * @param[out] eqNicknames The place to store calculated nicknames.
- *
- * @todo Should check unicity : check whether several names share the same initial,
- * or else capture consonants for example.
- */
-static void calcEqnsNicknames(const vector<string>& eqNames, vector<string>& eqNicknames)
-{
- //cerr << "###\n# Documentator : calcEqnsNicknames" << endl;
-
- vector<string> v;
-
- for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
- string init = calcDocEqnInitial(*eq);
- v.push_back(init);
- /** Check duplicates */
-// for( vector<string>::iterator it = v.begin(); it < v.end()-1; ++it ) {
-// if (init == *it) {
-// //cerr << "!! Warning Documentator : calcEqnsNicknames : duplicates \"" << init << "\"" << endl;
-// }
-// }
- eqNicknames.push_back(init);
- }
-
-// for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
-// int c = 0;
-// c = count_if(eqNames.begin(), eqNames.end(), bind2nd(equal_to<string>(), *eq));
-// if (c > 0) {
-// cerr << "- Duplicate nickname !! " << *eq << endl;
-// } else {
-// cerr << "(no duplicate) " << *eq << endl;
-// }
-// }
-
- //cerr << "Documentator : end of calcEqnsNicknames\n---" << endl;
-}
-
-
-/**
- * #4&5. Propagate and prepare every doc <equation>.
- *
- * Call boxPropagateSig, deBruijn2Sym, simplify, and privatise.
- *
- * @param[in] evalEqBoxes Equations boxes to propagate as signals.
- * @param[out] eqSigs The place to store prepared signals.
- */
-static void mapPrepareEqSig(const vector<Tree>& evalEqBoxes, vector<int>& eqInputs, vector<int>& eqOutputs, vector<Tree>& eqSigs)
-{
- //cerr << "###\n# Documentator : mapPrepareEqSig" << endl;
-
- for( vector<Tree>::const_iterator eq = evalEqBoxes.begin(); eq < evalEqBoxes.end(); eq++ ) {
-
- int numInputs, numOutputs;
- getBoxInputsAndOutputs(*eq, numInputs, numOutputs);
- //cerr << numInputs <<" ins and " << numOutputs <<" outs" << endl;
- eqInputs.push_back(numInputs);
- eqOutputs.push_back(numOutputs);
-
- Tree lsig1 = boxPropagateSig( nil, *eq , makeSigInputList(numInputs) );
- //cerr << "output signals are : " << endl; printSignal(lsig1, stderr);
-
- Tree lsig2 = deBruijn2Sym(lsig1); ///< Convert debruijn recursion into symbolic recursion
- Tree lsig3 = simplify(lsig2); ///< Simplify by executing every computable operation
- //Tree lsig4 = privatise(lsig3); ///< Un-share tables with multiple writers
- Tree lsig4 = docTableConvertion(lsig3); ///< convert regular tables into special doctables
- ///< (regular tables are difficult to translate to equations)
-
- eqSigs.push_back(lsig4);
- }
- //cerr << "Documentator : end of mapPrepareEqSig\n---" << endl;
-}
-
-
-/**
- * #6. Set signals nicknames.
- *
- * Do nothing for the moment !
- * @param[in] eqNicknames Contains previously calculated nicknames.
- * @param[out] eqSigs The signals to tag with a NICKNAMEPROPERTY.
- */
-static void mapSetSigNickname(const vector<string>& eqNicknames, const vector<int>& eqInputs, const vector<Tree>& eqSigs)
-{
- //cerr << "###\n# Documentator : mapSetSigNickname" << endl;
-
-// Do nothing for the moment...
-// for( unsigned int i=0; i < eqSigs.size(); i++ ) {
-// if (eqInputs[i] == 0) // Only "generators" should be finally named with user equation (nick)name.
-// setSigListNickName(eqSigs[i], eqNicknames[i]);
-// }
- //cerr << "Documentator : end of mapSetSigNickname\n---" << endl;
-}
-
-
-/**
- * #7. Collect each prepared list of signals to construct a super list.
- *
- * @param[in] eqSigs Contains well-prepared and nicknamed signals.
- * @param[out] superEqList The root where to 'cons' signals all together.
- */
-static void collectEqSigs(const vector<Tree>& eqSigs, Tree& superEqList)
-{
- //cerr << "###\n# Documentator : collectEqSigs" << endl;
-
- superEqList = nil;
-
- for( vector<Tree>::const_iterator it = eqSigs.begin(); it < eqSigs.end(); ++it ) {
- superEqList = cons( *it, superEqList );
- }
- //printSignal(superEqList, stdout, 0);
-
- //cerr << endl << "Documentator : end of collectEqSigs\n---" << endl;
-}
-
-
-/**
- * #8. Annotate superEqList (to find candidate signals to be named later).
- *
- * @param[in] DC The signals compiler.
- * @param[out] superEqList The super equations signal tree to annotate.
- */
-static void annotateSuperList(DocCompiler* DC, Tree superEqList)
-{
- DC->annotate(superEqList);
-}
-
-
-///**
-// * #9. Calculated and set lateq (LaTeX equation) names.
-// * Note : Transfered into mapCompileDocEqnSigs (DocCompiler::compileMultiSignal).
-// */
-//static void calcAndSetLtqNames(Tree superEqList)
-//{
-//
-//}
-
-
-/**
- * #10. Name and compile prepared doc <equation> signals.
- *
- * @param[in] eqSigs Contains well-prepared and nicknamed signals.
- * @param[in] DC The signals compiler.
- * @param[out] docCompiledEqnsVector The place to store each compiled Lateq* object.
- */
-static void mapCompileDocEqnSigs(const vector<Tree>& eqSigs, const vector<int>& eqInputs, const vector<int>& eqOutputs, DocCompiler* DC, vector<Lateq*>& docCompiledEqnsVector)
-{
- //cerr << "###\n# Documentator : mapCompileDocEqnSigs" << endl;
-
- for( unsigned int i=0; i < eqSigs.size(); i++ ) {
-
- // docCompiledEqnsVector.push_back( DC->compileMultiSignal(*it, 0) );
- docCompiledEqnsVector.push_back( DC->compileLateq(eqSigs[i], new Lateq(eqInputs[i], eqOutputs[i])) );
- }
-
- //cerr << "Documentator : end of mapCompileDocEqnSigs\n---" << endl;
-}
-
-
-
-/*****************************************************************************
- Secondary sub-functions for <equation> handling
- *****************************************************************************/
-
-
-/**
- * Calculate an appropriate nickname for equations,
- * from previous names.
- *
- * @param The string to parse.
- * @return Essentially returns the initial character,
- * except "Y" for "process", and "Z" for unnamed equations.
- */
-static string calcDocEqnInitial(const string s)
-{
- string nn;
- if(s == "process")
- nn = "Y";
- else if (s.substr(0,6) == "doceqn")
- nn = "Z";
- else
- nn += toupper(s[0]);
- return nn;
-}
-
-
-/**
- * Just get the number of inputs and the number of outputs of a box.
- *
- * @param[in] t The box tree to get inputs and outputs from.
- * @param[out] numInputs The place to store the number of inputs.
- * @param[out] numOutputs The place to store the number of outputs.
- */
-static void getBoxInputsAndOutputs(const Tree t, int& numInputs, int& numOutputs)
-{
- if (!getBoxType(t, &numInputs, &numOutputs)) {
- cerr << "ERROR during the evaluation of t : " << boxpp(t) << endl;
- exit(1);
- }
- //cerr << "Documentator : " << numInputs <<" inputs and " << numOutputs <<" outputs for box : " << boxpp(t) << endl;
-}
-
-
-/**
- * Print doc equations, following the Lateq::println method.
- *
- * @param[in] ltq The object containing compiled LaTeX code of equations.
- * @param[out] docout The output file to print into.
- */
-static void printDocEqn(Lateq* ltq, ostream& docout)
-{
- ltq->println(docout);
- //cerr << "Documentator : printDocEqn : "; ltq->println(cerr); cerr << endl;
-}
-
-
-/*****************************************************************************
- Sub-function for <diagram> handling
- *****************************************************************************/
-
-/**
- * @brief Doc diagrams handling.
- *
- * Three steps :
- * 1. evaluate expression
- * 2. call svg drawing in the appropriate directory
- * 3. print latex figure code with the appropriate directory reference
- *
- * @param[in] expr Parsed input expression, as boxes tree.
- * @param[in] svgTopDir Basename of the new doc directory ("*-math/svg").
- * @param[out] docout The output file to print into.
- */
-static void printDocDgm(const Tree expr, const char* svgTopDir, ostream& docout, int i)
-{
- /** 1. Evaluate expression. */
- Tree docdgm = evaldocexpr(expr, gExpandedDefList);
- if (gErrorCount > 0) {
- cerr << "Total of " << gErrorCount << " errors during evaluation of : diagram docdgm = " << boxpp(docdgm) << ";\n";
- exit(1);
- }
-
- /**
- * 2. Draw the diagram after its evaluation, in SVG.
- * Warning : pdflatex can't directly include SVG files !
- */
- char dgmid[MAXIDCHARS+1];
- sprintf(dgmid, "%02d", i);
- string thisdgmdir = subst("$0/svg-$1", svgTopDir, dgmid);
- //cerr << "Documentator : printDocDgm : drawSchema in '" << gCurrentDir << "/" << thisdgmdir << "'" << endl;
-
- drawSchema( docdgm, thisdgmdir.c_str(), "svg" );
-
- /** 3. Print LaTeX figure code. */
- char temp[1024];
- const string dgmfilename = legalFileName(docdgm, 1024, temp);
- //docout << "figure \\ref{figure" << i << "}";
- docout << "\\begin{figure}[ht!]" << endl;
- docout << "\t\\centering" << endl;
- docout << "\t\\includegraphics[width=\\textwidth]{" << subst("../svg/svg-$0/", dgmid) << dgmfilename << "}" << endl;
- docout << "\t\\caption{" << gDocMathStringMap["dgmcaption"] << " \\texttt{" << dgmfilename << "}}" << endl;
- docout << "\t\\label{figure" << i << "}" << endl;
- docout << "\\end{figure}" << endl << endl;
-
- /** 4. Warn about naming interferences (in the notice). */
- gDocNoticeFlagMap["nameconflicts"] = true;
- gDocNoticeFlagMap["svgdir"] = true;
-}
-
-
-
-/*****************************************************************************
- Other sub-functions
- *****************************************************************************/
-
-
-/**
- * Slice faust code between "mdoc" sections.
- *
- * @param[in] faustfile Name of the input faust file to parse.
- * @param[in] codeSlices The place to store code "slices".
- */
-vector<string>& docCodeSlicer(const string& faustfile, vector<string>& codeSlices)
-{
- string s;
- ifstream src;
- src.open(faustfile.c_str(), ifstream::in);
- string tmp = "";
-
- bool isInsideDoc = false;
-
- if (faustfile != "" && src.good()) {
- while(getline(src, s)) { /** Caution: we suppose there's only one <mdoc> tag per line! */
- size_t foundopendoc = s.find("<mdoc>");
-
- if (foundopendoc != string::npos) {
- if (isInsideDoc == false) { /** A change has come. ;) */
- if (! tmp.empty() ) {
- codeSlices.push_back(tmp); }
- tmp = "";
- }
- isInsideDoc = true;
- }
-
- if (isInsideDoc == false) {
- tmp += s + '\n';
- }
-
- size_t foundclosedoc = s.find("</mdoc>");
- if (foundclosedoc != string::npos) isInsideDoc = false;
- }
- } else {
- cerr << "ERROR : can't open faust source file " << faustfile << endl;
- exit(1);
- }
- return codeSlices;
-}
-
-
-/**
- * Print faust code inside a listing environment.
- *
- * @param[in] code Faust code as a string (may contain '\n' characters).
- * @param[out] docout The output file to print into.
- */
-static void printdocCodeSlices(const string& code, ostream& docout)
-{
- if ( ! code.empty() ) {
- docout << endl << "\\begin{lstlisting}[numbers=none, frame=none, basicstyle=\\small\\ttfamily, backgroundcolor=\\color{yobg}]" << endl;
- docout << code << endl;
- docout << "\\end{lstlisting}" << endl << endl;
- }
-}
-
-
-/**
- * Test whether a file does begin with some faust code or not.
- *
- * @param[in] faustfile Name of the input faust file to parse.
- */
-static bool doesFileBeginWithCode(const string& faustfile)
-{
- string s;
- ifstream src;
- src.open(faustfile.c_str(), ifstream::in);
-
- if (faustfile != "" && src.good()) {
- getline(src, s);
- size_t foundopendoc = s.find("<mdoc>");
- if(int(foundopendoc)==0) {
- return false;
- } else {
- return true;
- }
- } else {
- cerr << "ERROR : can't open faust source file " << faustfile << endl;
- exit(1);
- }
-}
-
-
-
-//------------------------ dealing with files -------------------------
-
-
-/**
- * Create a new directory in the current one.
- */
-static int makedir(const char* dirname)
-{
- char buffer[FAUST_PATH_MAX];
- gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
-
- if ( gCurrentDir.c_str() != 0) {
- int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
- if (status == 0 || errno == EEXIST) {
- return 0;
- }
- }
- perror("makedir");
- exit(errno);
-}
-
-
-/**
- * Create a new directory in the current one,
- * then 'cd' into this new directory.
- *
- * @remark
- * The current directory is saved to be later restaured.
- */
-static int mkchdir(const char* dirname)
-{
- char buffer[FAUST_PATH_MAX];
- gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
-
- if ( gCurrentDir.c_str() != 0) {
- int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
- if (status == 0 || errno == EEXIST) {
- if (chdir(dirname) == 0) {
- return 0;
- }
- }
- }
- perror("mkchdir");
- exit(errno);
-}
-
-
-/**
- * Switch back to the previously stored current directory
- */
-static int cholddir ()
-{
- if (chdir(gCurrentDir.c_str()) == 0) {
- return 0;
- } else {
- perror("cholddir");
- exit(errno);
- }
-}
-
-
-/**
- * Get current directory and store it in gCurrentDir.
- */
-static void getCurrentDir ()
-{
- char buffer[FAUST_PATH_MAX];
- gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
-}
-
-
-/**
- * Open architecture file.
- */
-static istream* openArchFile (const string& filename)
-{
- istream* file;
- getCurrentDir(); // Save the current directory.
- //cerr << "Documentator : openArchFile : Opening input file '" << filename << "'" << endl;
- if ( (file = open_arch_stream(filename.c_str())) ) {
- //cerr << "Documentator : openArchFile : Opening '" << filename << "'" << endl;
- } else {
- cerr << "ERROR : can't open architecture file " << filename << endl;
- exit(1);
- }
- cholddir(); // Return to current directory.
- return file;
-}
-
-
-/**
- * Transform the definition name property of tree <t> into a
- * legal file name. The resulting file name is stored in
- * <dst> a table of at least <n> chars. Returns the <dst> pointer
- * for convenience.
- */
-static char* legalFileName(const Tree t, int n, char* dst)
-{
- Tree id;
- int i=0;
- if (getDefNameProperty(t, id)) {
- const char* src = tree2str(id);
- for (i=0; isalnum(src[i]) && i<16; i++) {
- dst[i] = src[i];
- }
- }
- dst[i] = 0;
- if (strcmp(dst, "process") != 0) {
- // if it is not process add the hex address to make the name unique
- snprintf(&dst[i], n-i, "-%p", t);
- }
- return dst;
-}
-
-/**
- * Simply concat a string with a number in a "%03d" format.
- * The number has MAXIDCHARS characters.
- **/
-static string calcNumberedName(const char* base, int i)
-{
- char nb[MAXIDCHARS+1];
- sprintf(nb, "%03d", i);
- return subst("$0$1", base, nb);
-}
-
-/**
- * Remove the leading and trailing double quotes of a string
- * (but not those in the middle of the string)
- */
-static string rmExternalDoubleQuotes(const string& s)
-{
- size_t i = s.find_first_not_of("\"");
- size_t j = s.find_last_not_of("\"");
-
- if ( (i != string::npos) & (j != string::npos) ) {
- return s.substr(i, 1+j-i);
- } else {
- return "";
- }
-}
-
-
-/**
- * Copy all Faust source files into an 'src' subdirectory.
- *
- * @param[in] projname Basename of the new doc directory ("*-math").
- * @param[in] pathnames The paths list of the source files to copy.
- */
-static void copyFaustSources(const char* projname, const vector<string>& pathnames)
-{
- string srcdir = subst("$0/src", projname);
- //cerr << "Documentator : copyFaustSources : Creating directory '" << srcdir << "'" << endl;
- makedir(srcdir.c_str()); // create a directory.
-
- for (unsigned int i=0; i< pathnames.size(); i++) {
- ifstream src;
- ofstream dst;
- string faustfile = pathnames[i];
- string copy = subst("$0/$1", srcdir, filebasename(faustfile.c_str()));
- //cerr << "Documentator : copyFaustSources : Opening input file '" << faustfile << "'" << endl;
- //cerr << "Documentator : copyFaustSources : Opening output file '" << copy << "'" << endl;
- src.open(faustfile.c_str(), ifstream::in);
- dst.open(copy.c_str(), ofstream::out);
- string s;
- while ( getline(src,s) ) dst << s << endl;
- }
-}
-
-
-//------------------------ date managment -------------------------
-
-
-static void initCompilationDate()
-{
- time_t now;
-
- time(&now);
- gCompilationDate = *localtime(&now);
-}
-
-static struct tm* getCompilationDate()
-{
- initCompilationDate();
- return &gCompilationDate;
-}
-