FAUST compiler  0.9.9.6b8
doc.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003  FAUST compiler
00004  Copyright (C) 2009 GRAME, Centre National de Creation Musicale
00005  ---------------------------------------------------------------------
00006  This program is free software; you can redistribute it and/or modify
00007  it under the terms of the GNU General Public License as published by
00008  the Free Software Foundation; either version 2 of the License, or
00009  (at your option) any later version.
00010  
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU General Public License for more details.
00015  
00016  You should have received a copy of the GNU General Public License
00017  along with this program; if not, write to the Free Software
00018  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021 
00022 
00023 
00024 /*****************************************************************************
00025  ******************************************************************************
00026  
00027  
00028                         The Documentator Language
00029  
00030  
00031  ******************************************************************************
00032  *****************************************************************************/
00033 
00034 
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include <errno.h>
00046 #include <sys/stat.h>
00047 #include <time.h>
00048 #include <algorithm>
00049 #include <functional>
00050 
00051 #include <iostream>
00052 #include <fstream>
00053 #include <sstream>
00054 
00055 #include <map>
00056 #include <string>
00057 #include <vector>
00058 
00059 #include "ppbox.hh"
00060 #include "prim2.hh"
00061 #include "doc.hh"
00062 #include "eval.hh"
00063 #include "errormsg.hh"
00064 #include "doc_Text.hh"
00065 #include "sigprint.hh"
00066 #include "propagate.hh"
00067 #include "enrobage.hh"
00068 #include "drawschema.hh"
00069 #include "names.hh"
00070 #include "simplify.hh"
00071 #include "privatise.hh"
00072 #include "recursivness.hh"
00073 #include "sourcereader.hh"
00074 #include "lateq.hh"
00075 #include "doc_compile.hh"
00076 #include "doc_lang.hh"
00077 #include "doc_notice.hh"
00078 #include "doc_autodoc.hh"
00079 #include "compatibility.hh"
00080 
00081 
00082 
00083 #define MAXIDCHARS 5                ///< max numbers (characters) to represent ids (e.g. for directories).
00084 
00085 using namespace std ;
00086 
00087 
00088 /*****************************************************************************
00089                         Globals and prototyping
00090  *****************************************************************************/
00091 
00092 extern Tree                     gExpandedDefList;
00093 extern map<Tree, set<Tree> >    gMetaDataSet;
00094 extern map<string, string>      gDocMetadatasStringMap;
00095 extern map<string, string>      gDocMathStringMap;
00096 extern bool                     gDetailsSwitch;
00097 extern bool                     gStripDocSwitch;
00098 extern string                   gFaustDirectory;
00099 extern string                   gFaustSuperDirectory;
00100 extern string                   gFaustSuperSuperDirectory;
00101 extern string                   gMasterDocument;
00102 extern string                   gMasterName;
00103 extern SourceReader             gReader;
00104 
00105 extern string                   gDocName;               
00106 static const char*              gDocDevSuffix;          
00107 static string                   gCurrentDir;            
00108 static const string             gLatexheaderfilename = "latexheader.tex";
00109 
00110 vector<Tree>                    gDocVector;             
00111 
00112 static struct tm                gCompilationDate;
00113 
00114 bool                            gLstDependenciesSwitch  = true; 
00115 bool                            gLstMdocTagsSwitch      = true; 
00116 bool                            gLstDistributedSwitch   = true; 
00117 
00118 enum { langEN, langFR, langIT };
00119 string              gDocLang;
00120 
00121 /* Printing functions */
00122 static void     printlatexheader(istream& latexheader, const string& faustversion, ostream& docout);
00123 static void     printfaustlistings(ostream& docout);
00124 static void     printfaustlisting(string& path, ostream& docout);
00125 static void     printlatexfooter(ostream& docout);
00126 static void     printdoccontent(const char* svgTopDir, const vector<Tree>& docVector, const string& faustversion, ostream& docout);
00127 static void     printfaustdocstamp(const string& faustversion, ostream& docout);
00128 static void     printDocEqn(Lateq* ltq, ostream& docout);
00129 static void     printDocDgm(const Tree expr, const char* svgTopDir, ostream& docout, int i);
00130 static void     printDocMetadata(const Tree expr, ostream& docout);
00131 
00132 /* Primary sub-functions for <equation> handling */
00133 static void prepareDocEqns( const vector<Tree>& docBoxes, vector<Lateq*>& docCompiledEqnsVector );      
00134 static void collectDocEqns( const vector<Tree>& docBoxes, vector<Tree>& eqBoxes );                      
00135 static void mapEvalDocEqn( const vector<Tree>& eqBoxes, const Tree& env, vector<Tree>& evalEqBoxes );   
00136 static void mapGetEqName( const vector<Tree>& evalEqBoxes, vector<string>& eqNames );                   
00137 static void calcEqnsNicknames( const vector<string>& eqNames, vector<string>& eqNicknames );            
00138 static void mapPrepareEqSig( const vector<Tree>& evalEqBoxes, vector<int>& eqInputs, vector<int>& eqOutputs, vector<Tree>& eqSigs );    
00139 static void mapSetSigNickname( const vector<string>& eqNicknames, const vector<int>& eqInputs, const vector<Tree>& eqSigs );    
00140 static void collectEqSigs( const vector<Tree>& eqSigs, Tree& superEqList );                             
00141 static void annotateSuperList( DocCompiler* DC, Tree superEqList );                             
00142 //static void   calcAndSetLtqNames( Tree superEqList );     ///< step 9. 
00143 static void mapCompileDocEqnSigs( const vector<Tree>& eqSigs, const vector<int>& eqInputs, const vector<int>& eqOutputs, DocCompiler* DC, vector<Lateq*>& docCompiledEqnsVector );  
00144 
00145 /* Secondary sub-functions for <equation> handling */
00146 static string   calcNumberedName(const char* base, int i);
00147 static void     getBoxInputsAndOutputs(const Tree t, int& numInputs, int& numOutputs);
00148 static string   calcDocEqnInitial(const string s);
00149 
00150 /* Notice related functions */
00151 static void     initCompilationDate();
00152 static struct tm* getCompilationDate();
00153 
00154 /* Files functions */
00155 static int      cholddir ();
00156 static int      mkchdir(const char* dirname);
00157 static int      makedir(const char* dirname);
00158 static void     getCurrentDir();
00159 static istream* openArchFile (const string& filename);
00160 static char*    legalFileName(const Tree t, int n, char* dst);
00161 static string   rmExternalDoubleQuotes(const string& s);
00162 static void     copyFaustSources(const char* projname, const vector<string>& pathnames);
00163 vector<string>& docCodeSlicer(const string& faustfile, vector<string>& codeSlices);
00164 static void     printdocCodeSlices(const string& code, ostream& docout);
00165 static bool     doesFileBeginWithCode(const string& faustfile);
00166 
00167 //static void       declareAutoDoc();
00168 
00169 
00170 
00171 /*****************************************************************************
00172                     Types of Documentation Elements
00173  *****************************************************************************/
00174 
00175 Sym DOCTXT = symbol ("DocTxt");
00176 Tree docTxt(const char* name)       { return tree( DOCTXT, tree(symbol(name)) ); }
00177 bool isDocTxt(Tree t)               { return t->node() == Node(DOCTXT); }
00178 bool isDocTxt(Tree t0, const char** str)
00179 {
00180     Tree t1; Sym s;
00181     if ( isTree(t0, DOCTXT, t1) && isSym(t1->node(), &s) ) {
00182         *str = name(s);
00183         return true;
00184     } else {
00185         return false;
00186     }
00187 }
00188 
00189 Sym DOCEQN = symbol ("DocEqn");
00190 Tree docEqn(Tree x)                 { return tree(DOCEQN, x);       }
00191 bool isDocEqn(Tree t, Tree& x)      { return isTree(t, DOCEQN, x);  }
00192 
00193 Sym DOCDGM = symbol ("DocDgm");
00194 Tree docDgm(Tree x)                 { return tree(DOCDGM, x);       }
00195 bool isDocDgm(Tree t, Tree& x)      { return isTree(t, DOCDGM, x);  }
00196 
00197 Sym DOCNTC = symbol ("DocNtc");
00198 Tree docNtc()                       { return tree(DOCNTC);          }
00199 bool isDocNtc(Tree t)               { return isTree(t, DOCNTC);     }
00200 
00201 Sym DOCLST = symbol ("DocLst");
00202 Tree docLst()                       { return tree(DOCLST);          }
00203 bool isDocLst(Tree t)               { return isTree(t, DOCLST);     }
00204 
00205 Sym DOCMTD = symbol ("DocMtd");
00206 Tree docMtd(Tree x)                 { return tree(DOCMTD, x);       }
00207 bool isDocMtd(Tree t, Tree& x)      { return isTree(t, DOCMTD, x);  }
00208 
00209 //string getDocTxt(Tree t)          { return hd(t)->branch(0); }
00210 
00211 
00212 
00213 /*****************************************************************************
00214                 Main Printing Function for the Documentation
00215  *****************************************************************************/
00216 
00217 
00229 void printDoc(const char* projname, const char* docdev, const char* faustversion)
00230 {
00231     gDocDevSuffix = docdev;
00232     
00234     //cerr << "Documentator : printDoc : gFaustDirectory = '" << gFaustDirectory << "'" << endl;
00235     //cerr << "Documentator : printDoc : gFaustSuperDirectory = '" << gFaustSuperDirectory << "'" << endl;
00236     //cerr << "Documentator : printDoc : gFaustSuperSuperDirectory = '" << gFaustSuperSuperDirectory << "'" << endl;
00237     //cerr << "Documentator : printDoc : gCurrentDir = '" << gCurrentDir << "'" << endl;
00238     
00239     makedir(projname);          // create a top directory to store files
00240     
00241     string svgTopDir = subst("$0/svg", projname);
00242     makedir(svgTopDir.c_str()); // create a directory to store svg-* subdirectories.
00243     
00244     string cppdir = subst("$0/cpp", projname);
00245     makedir(cppdir.c_str());    // create a cpp directory.
00246     
00247     string pdfdir = subst("$0/pdf", projname);
00248     makedir(pdfdir.c_str());    // create a pdf directory.
00249     
00250     /* Copy all Faust source files into an 'src' sub-directory. */
00251     vector<string> pathnames = gReader.listSrcFiles();
00252     copyFaustSources(projname, pathnames);
00253     
00254     string texdir = subst("$0/tex", projname);
00255     mkchdir(texdir.c_str());    // create a directory and move into.
00256 
00258     ofstream docout(subst("$0.$1", gDocName, docdev).c_str());
00259     cholddir();                 // return to current directory
00260     
00262     loadTranslationFile(gDocLang);
00263     
00265     if (gDocVector.empty()) { declareAutoDoc(); }   
00266     
00268     printfaustdocstamp(faustversion, docout);                       
00269     istream* latexheader = openArchFile(gLatexheaderfilename);
00270     printlatexheader(*latexheader, faustversion, docout);                       
00271     printdoccontent(svgTopDir.c_str(), gDocVector, faustversion, docout);       
00272     printlatexfooter(docout);                                       
00273 }
00274 
00275 
00276 
00277 /*****************************************************************************
00278             LaTeX basic printing functions of the Documentation
00279  *****************************************************************************/
00280 
00288 static void printlatexheader(istream& latexheader, const string& faustversion, ostream& docout)
00289 {   
00290     string  s;
00291     while(getline(latexheader, s)) docout << s << endl;
00292     
00294     docout << "\\newcommand{\\faustfilename}{" << gMasterDocument << "}" << endl;
00295     docout << "\\newcommand{\\faustdocdir}{" << gMasterName << "-mdoc}" << endl;
00296     docout << "\\newcommand{\\faustprogname}{" << gMasterName << "}" << endl;
00297     docout << "\\newcommand{\\faustversion}{" << faustversion << "}" << endl;
00298     char datebuf [150];
00299     strftime (datebuf, 150, "%B %d, %Y", getCompilationDate());
00300     docout << "\\newcommand{\\faustdocdate}{" << datebuf << "}" << endl;
00301     
00302     docout << endl << "\\begin{document}" << endl;
00303 }
00304 
00305 
00316 static void printDocMetadata(const Tree expr, ostream& docout)
00317 {
00318     if (gMetaDataSet.count(expr)) {
00319         string sep = "";
00320         set<Tree> mset = gMetaDataSet[expr];
00321         
00322         for (set<Tree>::iterator j = mset.begin(); j != mset.end(); j++) {
00323             docout << sep << rmExternalDoubleQuotes(tree2str(*j));
00324             sep = ", ";
00325         }
00326     }
00327 }
00328 
00329 
00336 static void printfaustlistings(ostream& docout)
00337 {   
00338     if (gLstDependenciesSwitch) {
00339         vector<string> pathnames = gReader.listSrcFiles();
00340         for (unsigned int i=0; i< pathnames.size(); i++) {
00341             printfaustlisting(pathnames[i], docout);
00342         }
00343     } else {
00344         printfaustlisting(gMasterDocument, docout);
00345     }
00346 }
00347 
00348 
00356 static void printfaustlisting(string& faustfile, ostream& docout)
00357 {   
00358     string  s;
00359     ifstream src;
00360     
00361     //cerr << "Documentator : printfaustlisting : Opening file '" << faustfile << "'" << endl;
00362     src.open(faustfile.c_str(), ifstream::in);
00363     
00364     docout << endl << "\\bigskip\\bigskip" << endl;
00365     docout << "\\begin{lstlisting}[caption=\\texttt{" << filebasename(faustfile.c_str()) << "}]" << endl;
00366 
00367     bool isInsideDoc = false;
00368     
00369     if (faustfile != "" && src.good()) {
00370         while(getline(src, s)) { 
00371             size_t foundopendoc  = s.find("<mdoc>");
00372             if (foundopendoc != string::npos && gStripDocSwitch) isInsideDoc = true;
00373             
00374             if (isInsideDoc == false)
00375                 docout << s << endl;
00376             
00377             size_t foundclosedoc = s.find("</mdoc>");
00378             if (foundclosedoc != string::npos && gStripDocSwitch) isInsideDoc = false;
00379         }
00380     } else {
00381         cerr << "ERROR : can't open faust source file " << faustfile << endl;
00382         exit(1);
00383     }
00384     
00385     docout << "\\end{lstlisting}" << endl << endl;
00386 }
00387 
00388 
00394 static void printlatexfooter(ostream& docout)
00395 {
00396     docout << endl << "\\end{document}" << endl << endl;
00397 }
00398 
00399 
00409 static void printfaustdocstamp(const string& faustversion, ostream& docout)
00410 {
00411     char datebuf [150];
00412     strftime (datebuf, 150, "%c", getCompilationDate());
00413     
00414     docout << "%% This documentation was generated with Faust version " << faustversion << endl;
00415     docout << "%% " << datebuf << endl;
00416     docout << "%% http://faust.grame.fr" << endl << endl;
00417 }
00418 
00419 
00420 
00421 /*****************************************************************************
00422             Main loop : launches prepare, evaluate, and print functions
00423  *****************************************************************************/
00424 
00441 static void printdoccontent(const char* svgTopDir, const vector<Tree>& docVector, const string& faustversion, ostream& docout)
00442 {
00443     //cerr << endl << "Documentator : printdoccontent : " << docVector.size() << " <mdoc> tags read." << endl;
00444     
00446     vector<Lateq*>  docCompiledEqnsVector;
00447     prepareDocEqns( docVector, docCompiledEqnsVector ); 
00448     vector<Lateq*>::iterator eqn_it = docCompiledEqnsVector.begin();
00449     
00450     int dgmIndex = 1;           
00451 
00452     vector<string> docMasterCodeMap;
00453     docMasterCodeMap = docCodeSlicer(gMasterDocument, docMasterCodeMap);
00454     
00455     vector<Tree>::const_iterator doc;
00456     vector<string>::const_iterator code;
00457     code = docMasterCodeMap.begin();
00458     
00459     if(doesFileBeginWithCode(gMasterDocument) && (! docMasterCodeMap.empty()) && gLstDistributedSwitch ) {
00460         printdocCodeSlices(*code, docout);
00461         code++;
00462     }
00463     
00465     for (doc=docVector.begin(); doc<docVector.end(); doc++, code++) {
00466         
00467         Tree L = reverse(*doc);
00468         //cerr << "Entering into <mdoc> parsing..." << endl; 
00469         
00471         while (isList(L)) {
00472             Tree expr;
00473             if ( isDocEqn(hd(L), expr) ) { 
00474                 printDocEqn(*eqn_it++, docout);
00475             }
00476             else if ( isDocDgm(hd(L), expr) ) { 
00477                 printDocDgm(expr, svgTopDir, docout, dgmIndex++);
00478             }
00479             else if ( isDocMtd(hd(L), expr) ) { 
00480                 printDocMetadata(expr, docout);
00481             }
00482             else if ( isDocTxt(hd(L)) ) { 
00483                 docout << *hd(L)->branch(0); // Directly print registered doc text.
00484             }
00485             else if ( isDocNtc(hd(L)) ) { 
00486                 printDocNotice(faustversion, docout);
00487             }
00488             else if ( isDocLst(hd(L)) ) { 
00489                 printfaustlistings(docout);
00490             }
00491             else { 
00492                 cerr << "ERROR : " << *hd(L) << " is not a valid documentation type." << endl; 
00493             }
00494             L = tl(L);
00495         }
00496         //cerr << " ...end of <mdoc> parsing." << endl; 
00497         
00498         if ( code != docMasterCodeMap.end() && gLstDistributedSwitch ) {
00499             printdocCodeSlices(*code, docout);
00500         }
00501     }
00502 }
00503 
00504 
00505 
00506 /*****************************************************************************
00507             Primary sub-functions for <equation> handling
00508  *****************************************************************************/
00509 
00520 static void prepareDocEqns(const vector<Tree>& docBoxes, vector<Lateq*>& docCompiledEqnsVector)
00521 {   
00522     vector<Tree>    eqBoxes;        collectDocEqns( docBoxes, eqBoxes );        
00523     
00524     if(! eqBoxes.empty() ) {
00525         vector<Tree>    evalEqBoxes;    mapEvalDocEqn( eqBoxes, gExpandedDefList, evalEqBoxes );    
00526         vector<string>  eqNames;        mapGetEqName( evalEqBoxes, eqNames );       
00527         vector<string>  eqNicknames;    calcEqnsNicknames( eqNames, eqNicknames );  
00528         
00529         vector<int>     eqInputs;
00530         vector<int>     eqOutputs;
00531         vector<Tree>    eqSigs;         mapPrepareEqSig( evalEqBoxes, eqInputs, eqOutputs, eqSigs );    
00532         mapSetSigNickname( eqNicknames, eqInputs, eqSigs );                                 
00533         Tree            superEqList;    collectEqSigs( eqSigs, superEqList );       
00534         
00535         DocCompiler* DC = new DocCompiler(0, 0);
00536         annotateSuperList( DC, superEqList );                                       
00537         //calcAndSetLtqNames( superEqList );                                        ///< step 9. (directly in 10.)
00538         mapCompileDocEqnSigs( eqSigs, eqInputs, eqOutputs, DC, docCompiledEqnsVector );     
00539     }
00540 }
00541 
00542 
00549 static void collectDocEqns(const vector<Tree>& docBoxes, vector<Tree>& eqBoxes)
00550 {
00551     int nbdoceqn = 0;
00552     
00553     for (vector<Tree>::const_iterator doc=docBoxes.begin(); doc<docBoxes.end(); doc++) {
00554         Tree L = reverse(*doc);
00555         Tree expr;
00556         while (isList(L)) {
00557             if ( isDocEqn(hd(L), expr) ) {
00558                 eqBoxes.push_back(expr);
00559                 nbdoceqn++;
00560             }
00561             L = tl(L);
00562         }
00563     }
00564     //cerr << "Documentator : collectDocEqns : " << nbdoceqn << " <equation> tags found." << endl;
00565 }
00566 
00567 
00575 static void mapEvalDocEqn(const vector<Tree>& eqBoxes, const Tree& env, vector<Tree>& evalEqBoxes)
00576 {
00577     //cerr << "###\n# Documentator : mapEvalDocEqn" << endl;
00578     
00579     for ( vector<Tree>::const_iterator eq=eqBoxes.begin(); eq < eqBoxes.end(); eq++)
00580     {
00581         evalEqBoxes.push_back(evaldocexpr( *eq, env ));
00582     }
00583     //cerr << "Documentator : end of mapEvalDocEqn\n---" << endl;
00584 }
00585 
00586 
00593 static void mapGetEqName(const vector<Tree>& evalEqBoxes, vector<string>& eqNames)
00594 {
00595     //cerr << "###\n# Documentator : mapGetEqName" << endl;
00596     
00597     int i = 1;
00598     for( vector<Tree>::const_iterator eq = evalEqBoxes.begin(); eq < evalEqBoxes.end(); eq++, i++ ) {
00599         Tree id;
00600         string s;
00601         int n,m; getBoxType(*eq, &n, &m); // eq name only for bd without inputs
00602         if ( n==0 && getDefNameProperty(*eq, id) ) {
00603             s = tree2str(id);
00604         }
00605         else {
00606             s = calcNumberedName("doceqn-", i);
00607         }       
00608         eqNames.push_back( s ) ;
00609     }
00610     //cerr << "Documentator : end of mapGetEqName\n---" << endl;
00611 }
00612 
00613 
00623 static void calcEqnsNicknames(const vector<string>& eqNames, vector<string>& eqNicknames)
00624 {
00625     //cerr << "###\n# Documentator : calcEqnsNicknames" << endl;
00626     
00627     vector<string> v;
00628     
00629     for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
00630         string init = calcDocEqnInitial(*eq);
00631         v.push_back(init);
00633 //      for( vector<string>::iterator it = v.begin(); it < v.end()-1; ++it ) {
00634 //          if (init == *it) {
00635 //              //cerr << "!! Warning Documentator : calcEqnsNicknames : duplicates \"" << init << "\"" << endl;
00636 //          }
00637 //      }
00638         eqNicknames.push_back(init);
00639     }
00640     
00641 //  for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
00642 //      int c = 0;
00643 //      c = count_if(eqNames.begin(), eqNames.end(), bind2nd(equal_to<string>(), *eq));
00644 //      if (c > 0) { 
00645 //          cerr << "- Duplicate nickname !! " << *eq << endl; 
00646 //      } else {
00647 //          cerr << "(no duplicate) " << *eq << endl;
00648 //      }
00649 //  }
00650     
00651     //cerr << "Documentator : end of calcEqnsNicknames\n---" << endl;
00652 }
00653 
00654 
00663 static void mapPrepareEqSig(const vector<Tree>& evalEqBoxes, vector<int>& eqInputs, vector<int>& eqOutputs, vector<Tree>& eqSigs)
00664 {
00665     //cerr << "###\n# Documentator : mapPrepareEqSig" << endl;
00666     
00667     for( vector<Tree>::const_iterator eq = evalEqBoxes.begin(); eq < evalEqBoxes.end(); eq++ ) {
00668         
00669         int numInputs, numOutputs;
00670         getBoxInputsAndOutputs(*eq, numInputs, numOutputs);
00671         //cerr << numInputs <<" ins and " << numOutputs <<" outs" << endl;
00672         eqInputs.push_back(numInputs);
00673         eqOutputs.push_back(numOutputs);
00674         
00675         Tree lsig1 = boxPropagateSig( nil, *eq , makeSigInputList(numInputs) );
00676         //cerr << "output signals are : " << endl;  printSignal(lsig1, stderr);
00677         
00678         Tree lsig2 = deBruijn2Sym(lsig1);   
00679         Tree lsig3 = simplify(lsig2);       
00680         //Tree lsig4 = privatise(lsig3);        ///< Un-share tables with multiple writers
00681         Tree lsig4 = docTableConvertion(lsig3);     
00682 
00683 
00684         eqSigs.push_back(lsig4);
00685     }
00686     //cerr << "Documentator : end of mapPrepareEqSig\n---" << endl;
00687 }
00688 
00689 
00697 static void mapSetSigNickname(const vector<string>& eqNicknames, const vector<int>& eqInputs, const vector<Tree>& eqSigs)
00698 {
00699     //cerr << "###\n# Documentator : mapSetSigNickname" << endl;
00700 
00701 //  Do nothing for the moment...
00702 //  for( unsigned int i=0; i < eqSigs.size(); i++ ) {
00703 //      if (eqInputs[i] == 0) // Only "generators" should be finally named with user equation (nick)name.
00704 //          setSigListNickName(eqSigs[i], eqNicknames[i]);
00705 //  }
00706     //cerr << "Documentator : end of mapSetSigNickname\n---" << endl;
00707 }
00708 
00709 
00716 static void collectEqSigs(const vector<Tree>& eqSigs, Tree& superEqList)
00717 {
00718     //cerr << "###\n# Documentator : collectEqSigs" << endl;
00719     
00720     superEqList = nil;
00721     
00722     for( vector<Tree>::const_iterator it = eqSigs.begin(); it < eqSigs.end(); ++it ) {
00723         superEqList = cons( *it, superEqList );
00724     }
00725     //printSignal(superEqList, stdout, 0);
00726     
00727     //cerr << endl << "Documentator : end of collectEqSigs\n---" << endl;
00728 }
00729 
00730 
00737 static void annotateSuperList(DocCompiler* DC, Tree superEqList)
00738 {
00739     DC->annotate(superEqList);
00740 }
00741 
00742 
00744 // * #9. Calculated and set lateq (LaTeX equation) names.
00745 // * Note : Transfered into mapCompileDocEqnSigs (DocCompiler::compileMultiSignal).
00746 // */
00747 //static void   calcAndSetLtqNames(Tree superEqList)
00748 //{
00749 //  
00750 //}
00751 
00752 
00760 static void mapCompileDocEqnSigs(const vector<Tree>& eqSigs, const vector<int>& eqInputs, const vector<int>& eqOutputs, DocCompiler* DC, vector<Lateq*>& docCompiledEqnsVector)
00761 {
00762     //cerr << "###\n# Documentator : mapCompileDocEqnSigs" << endl;
00763     
00764     for( unsigned int i=0; i < eqSigs.size(); i++ ) {
00765         
00766         //      docCompiledEqnsVector.push_back( DC->compileMultiSignal(*it, 0) );
00767         docCompiledEqnsVector.push_back( DC->compileLateq(eqSigs[i], new Lateq(eqInputs[i], eqOutputs[i])) );
00768     }
00769     
00770     //cerr << "Documentator : end of mapCompileDocEqnSigs\n---" << endl;
00771 }
00772 
00773 
00774 
00775 /*****************************************************************************
00776                 Secondary sub-functions for <equation> handling
00777  *****************************************************************************/
00778 
00779 
00788 static string calcDocEqnInitial(const string s)
00789 {
00790     string nn;
00791     if(s == "process")
00792         nn = "Y";
00793     else if (s.substr(0,6) == "doceqn")
00794         nn = "Z";
00795     else
00796         nn += toupper(s[0]);
00797     return nn;
00798 }
00799 
00800 
00808 static void getBoxInputsAndOutputs(const Tree t, int& numInputs, int& numOutputs)
00809 {
00810     if (!getBoxType(t, &numInputs, &numOutputs)) {
00811         cerr << "ERROR during the evaluation of t : " << boxpp(t) << endl;
00812         exit(1);
00813     }
00814     //cerr << "Documentator : " << numInputs <<" inputs and " << numOutputs <<" outputs for box : " << boxpp(t) << endl;
00815 }
00816 
00817 
00824 static void printDocEqn(Lateq* ltq, ostream& docout) 
00825 {
00826     ltq->println(docout);
00827     //cerr << "Documentator : printDocEqn : "; ltq->println(cerr); cerr << endl;
00828 }
00829 
00830 
00831 /*****************************************************************************
00832                     Sub-function for <diagram> handling
00833  *****************************************************************************/
00834 
00847 static void printDocDgm(const Tree expr, const char* svgTopDir, ostream& docout, int i)
00848 {
00850     Tree docdgm = evaldocexpr(expr, gExpandedDefList);
00851     if (gErrorCount > 0) {
00852         cerr << "Total of " << gErrorCount << " errors during evaluation of : diagram docdgm = " << boxpp(docdgm) << ";\n";
00853         exit(1);
00854     }
00855     
00860     char dgmid[MAXIDCHARS+1];
00861     sprintf(dgmid, "%02d", i);
00862     string thisdgmdir = subst("$0/svg-$1", svgTopDir, dgmid);
00863     //cerr << "Documentator : printDocDgm : drawSchema in '" << gCurrentDir << "/" << thisdgmdir << "'" << endl;
00864     
00865     drawSchema( docdgm, thisdgmdir.c_str(), "svg" );
00866     
00868     char temp[1024];
00869     const string dgmfilename = legalFileName(docdgm, 1024, temp);
00870     //docout << "figure \\ref{figure" << i << "}";
00871     docout << "\\begin{figure}[ht!]" << endl;
00872     docout << "\t\\centering" << endl;
00873     docout << "\t\\includegraphics[width=\\textwidth]{" << subst("../svg/svg-$0/", dgmid) << dgmfilename << "}" << endl;
00874     docout << "\t\\caption{" << gDocMathStringMap["dgmcaption"] << " \\texttt{" << dgmfilename << "}}" << endl;
00875     docout << "\t\\label{figure" << i << "}" << endl;
00876     docout << "\\end{figure}" << endl << endl;
00877     
00879     gDocNoticeFlagMap["nameconflicts"] = true;
00880     gDocNoticeFlagMap["svgdir"] = true;
00881 }
00882 
00883 
00884 
00885 /*****************************************************************************
00886                             Other sub-functions
00887  *****************************************************************************/
00888 
00889 
00896 vector<string>& docCodeSlicer(const string& faustfile, vector<string>& codeSlices)
00897 {
00898     string  s;
00899     ifstream src;
00900     src.open(faustfile.c_str(), ifstream::in);
00901     string tmp = "";
00902     
00903     bool isInsideDoc = false;
00904     
00905     if (faustfile != "" && src.good()) {
00906         while(getline(src, s)) { 
00907             size_t foundopendoc  = s.find("<mdoc>");
00908             
00909             if (foundopendoc != string::npos) { 
00910                 if (isInsideDoc == false) { 
00911                     if (! tmp.empty() ) {
00912                         codeSlices.push_back(tmp); }
00913                     tmp = "";
00914                 }
00915                 isInsideDoc = true;  
00916             }
00917             
00918             if (isInsideDoc == false) {
00919                 tmp += s + '\n';
00920             }
00921             
00922             size_t foundclosedoc = s.find("</mdoc>");
00923             if (foundclosedoc != string::npos) isInsideDoc = false;
00924         }
00925     } else {
00926         cerr << "ERROR : can't open faust source file " << faustfile << endl;
00927         exit(1);
00928     }
00929     return codeSlices;
00930 }
00931             
00932 
00939 static void printdocCodeSlices(const string& code, ostream& docout)
00940 {
00941     if ( ! code.empty() ) {
00942         docout << endl << "\\begin{lstlisting}[numbers=none, frame=none, basicstyle=\\small\\ttfamily, backgroundcolor=\\color{yobg}]" << endl;
00943         docout << code << endl;
00944         docout << "\\end{lstlisting}" << endl << endl;
00945     }
00946 }
00947 
00948 
00954 static bool doesFileBeginWithCode(const string& faustfile)
00955 {
00956     string  s;
00957     ifstream src;
00958     src.open(faustfile.c_str(), ifstream::in);
00959     
00960     if (faustfile != "" && src.good()) {
00961         getline(src, s);
00962         size_t foundopendoc = s.find("<mdoc>");
00963         if(int(foundopendoc)==0) {
00964             return false;
00965         } else {
00966             return true;
00967         }
00968     } else {
00969         cerr << "ERROR : can't open faust source file " << faustfile << endl;
00970         exit(1);
00971     }
00972 }   
00973 
00974 
00975 
00976 //------------------------ dealing with files -------------------------
00977 
00978 
00982 static int makedir(const char* dirname)
00983 {
00984     char    buffer[FAUST_PATH_MAX];
00985     gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
00986     
00987     if ( gCurrentDir.c_str() != 0) {
00988         int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
00989         if (status == 0 || errno == EEXIST) {
00990             return 0;
00991         }
00992     }
00993     perror("makedir");
00994     exit(errno);
00995 }
00996 
00997 
01005 static int mkchdir(const char* dirname)
01006 {
01007     char    buffer[FAUST_PATH_MAX];
01008     gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
01009 
01010     if ( gCurrentDir.c_str() != 0) {
01011         int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
01012         if (status == 0 || errno == EEXIST) {
01013             if (chdir(dirname) == 0) {
01014                 return 0;
01015             }
01016         }
01017     }
01018     perror("mkchdir");
01019     exit(errno);
01020 }
01021 
01022 
01026 static int cholddir ()
01027 {
01028     if (chdir(gCurrentDir.c_str()) == 0) {
01029         return 0;
01030     } else {
01031         perror("cholddir");
01032         exit(errno);
01033     }
01034 }
01035 
01036 
01040 static void getCurrentDir ()
01041 {
01042     char    buffer[FAUST_PATH_MAX];
01043     gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
01044 }
01045 
01046 
01050 static istream* openArchFile (const string& filename)
01051 {
01052     istream* file;
01053     getCurrentDir();    // Save the current directory.
01054     //cerr << "Documentator : openArchFile : Opening input file  '" << filename << "'" << endl;
01055     if ( (file = open_arch_stream(filename.c_str())) ) {
01056         //cerr << "Documentator : openArchFile : Opening '" << filename << "'" << endl;
01057     } else {
01058         cerr << "ERROR : can't open architecture file " << filename << endl;
01059         exit(1);
01060     }
01061     cholddir();         // Return to current directory.
01062     return file;
01063 }
01064 
01065 
01072 static char* legalFileName(const Tree t, int n, char* dst)
01073 {
01074     Tree    id;
01075     int     i=0;
01076     if (getDefNameProperty(t, id)) {
01077         const char*     src = tree2str(id);
01078         for (i=0; isalnum(src[i]) && i<16; i++) {
01079             dst[i] = src[i];
01080         }
01081     }
01082     dst[i] = 0;
01083     if (strcmp(dst, "process") != 0) { 
01084         // if it is not process add the hex address to make the name unique
01085         snprintf(&dst[i], n-i, "-%p", t);
01086     }
01087     return dst;
01088 }
01089 
01094 static string calcNumberedName(const char* base, int i)
01095 {
01096     char nb[MAXIDCHARS+1];
01097     sprintf(nb, "%03d", i);
01098     return subst("$0$1", base, nb);
01099 }
01100 
01105 static string rmExternalDoubleQuotes(const string& s)
01106 {
01107     size_t i = s.find_first_not_of("\"");
01108     size_t j = s.find_last_not_of("\"");
01109     
01110     if ( (i != string::npos) & (j != string::npos) ) {
01111         return s.substr(i, 1+j-i);
01112     } else {
01113         return "";
01114     }
01115 }
01116 
01117 
01124 static void copyFaustSources(const char* projname, const vector<string>& pathnames)
01125 {
01126     string srcdir = subst("$0/src", projname);
01127     //cerr << "Documentator : copyFaustSources : Creating directory '" << srcdir << "'" << endl;
01128     makedir(srcdir.c_str());    // create a directory.
01129         
01130     for (unsigned int i=0; i< pathnames.size(); i++) {
01131         ifstream src;
01132         ofstream dst;
01133         string faustfile = pathnames[i];
01134         string copy = subst("$0/$1", srcdir, filebasename(faustfile.c_str()));
01135         //cerr << "Documentator : copyFaustSources : Opening input file  '" << faustfile << "'" << endl;
01136         //cerr << "Documentator : copyFaustSources : Opening output file '" << copy << "'" << endl;
01137         src.open(faustfile.c_str(), ifstream::in);
01138         dst.open(copy.c_str(), ofstream::out);
01139         string  s;
01140         while ( getline(src,s) ) dst << s << endl;
01141     }
01142 }
01143 
01144 
01145 //------------------------ date managment -------------------------
01146 
01147 
01148 static void initCompilationDate()
01149 {
01150     time_t now;
01151     
01152     time(&now);
01153     gCompilationDate = *localtime(&now);
01154 }
01155 
01156 static struct tm* getCompilationDate()
01157 {
01158     initCompilationDate();
01159     return &gCompilationDate;
01160 }
01161