/tags/rel-0-6-0/FreeSpeech/data-flow/src/UIDocument.cc

# · C++ · 652 lines · 511 code · 89 blank · 52 comment · 89 complexity · bacedf5009af4bd69df79f660a2e99bc MD5 · raw file

  1. // Copyright (C) 2001 Jean-Marc Valin
  2. #include "path.h"
  3. #include <tree.h>
  4. #include <parser.h>
  5. #include "UIDocument.h"
  6. #include "UINetwork.h"
  7. #include "Node.h"
  8. #include "Network.h"
  9. #include "ParameterSet.h"
  10. #include <sys/stat.h>
  11. #include <dlfcn.h>
  12. #include <sys/types.h>
  13. #include <dirent.h>
  14. #include <unistd.h>
  15. #include <sstream>
  16. #include <fstream>
  17. #include <fcntl.h>
  18. #include "stream_wrap.h"
  19. //@implements UIClasses
  20. UIDocument::UIDocument(string _name)
  21. : modified(false)
  22. , docName(_name)
  23. , untitled(true)
  24. {
  25. }
  26. UIDocument::~UIDocument()
  27. {
  28. //cerr << "destroying UIDocument " << name << endl;
  29. for (unsigned int i=0;i<networks.size();i++)
  30. delete networks[i];
  31. for (unsigned int i=0;i<textParams.size();i++)
  32. delete textParams[i];
  33. for (unsigned int i=0;i<docInputs.size();i++)
  34. delete docInputs[i];
  35. for (unsigned int i=0;i<docOutputs.size();i++)
  36. delete docOutputs[i];
  37. for (unsigned int i=0;i<docParams.size();i++)
  38. delete docParams[i];
  39. }
  40. UINetwork *UIDocument::getNetworkNamed(const string &n)
  41. {
  42. for (unsigned int i=0;i<networks.size();i++)
  43. {
  44. if (networks[i]->getName() == n)
  45. return networks[i];
  46. }
  47. return NULL;
  48. }
  49. vector<ItemInfo *> UIDocument::getNetInputs(const string &netName)
  50. {
  51. //updateAllNetworks();
  52. vector <ItemInfo *> inputs;
  53. if (subnetInfo.findNode(netName))
  54. return subnetInfo.findNode(netName)->inputs;
  55. return inputs;
  56. }
  57. vector<ItemInfo *> UIDocument::getNetOutputs(const string &netName)
  58. {
  59. //updateAllNetworks();
  60. vector <ItemInfo *> outputs;
  61. if (subnetInfo.findNode(netName))
  62. return subnetInfo.findNode(netName)->outputs;
  63. return outputs;
  64. }
  65. vector<ItemInfo *> UIDocument::getNetParams(const string &netName)
  66. {
  67. //updateAllNetworks();
  68. vector <ItemInfo *> params;
  69. if (subnetInfo.findNode(netName))
  70. return subnetInfo.findNode(netName)->params;
  71. return params;
  72. }
  73. string UIDocument::getDescription(const string &type)
  74. {
  75. NodeInfo *info = UINodeRepository::Find(type);
  76. if (info)
  77. return info->description;
  78. else
  79. return "Description not available";
  80. }
  81. void UIDocument::addParameterText(string name, string value, string type)
  82. {
  83. DocParameterDataText *textInfo = new DocParameterDataText;
  84. textInfo->name = name;
  85. textInfo->value = value;
  86. textInfo->type = type;
  87. textParams.insert(textParams.end(), textInfo);
  88. }
  89. void UIDocument::printOn(ostream &out) const
  90. {
  91. out << "<UIDocument" << endl;
  92. out << "<name " << docName << " >" << endl;
  93. out << ">" << endl;
  94. }
  95. void UIDocument::load()
  96. {
  97. string fullpath=path+docName;
  98. /* This allows making scripts by ignoring the #! line at the beginning
  99. Unfortunately, it is incompatible with the compression feature of libXML*/
  100. //ostringstream docText;
  101. ifstream docFile(fullpath.c_str());
  102. if (docFile.fail())
  103. {
  104. error("Error: cannot open file");
  105. //cerr << "load: error loading " << fullpath << "\n";
  106. addNetwork("MAIN", UINetwork::subnet);
  107. resetModified();
  108. return;
  109. }
  110. char ch;
  111. docFile >> ch;
  112. if (ch=='#')
  113. {
  114. while (ch != '<')
  115. {
  116. docFile >> ch;
  117. if (docFile.fail())
  118. {
  119. error("Error: this doesn't look like an Overflow document");
  120. addNetwork("MAIN", UINetwork::subnet);
  121. resetModified();
  122. return;
  123. }
  124. }
  125. } else if (ch!='<')
  126. {
  127. error("Error: this doesn't look like an Overflow document");
  128. addNetwork("MAIN", UINetwork::subnet);
  129. resetModified();
  130. return;
  131. }
  132. string xmlStr;
  133. docFile >> xmlStr;
  134. if (xmlStr != "?xml")
  135. {
  136. error("Error: this doesn't look like an Overflow document");
  137. addNetwork("MAIN", UINetwork::subnet);
  138. resetModified();
  139. return;
  140. }
  141. //docFile.putback(ch);
  142. string docStr="<?xml";
  143. while(1)
  144. {
  145. char buff[1025];
  146. docFile.read(buff, 1024);
  147. buff[1024]=0;
  148. if (docFile.fail())
  149. {
  150. docStr.append(buff, docFile.gcount());
  151. break;
  152. }
  153. docStr.append(buff, 1024);
  154. }
  155. loadFromMemory(docStr.c_str(), docStr.size());
  156. }
  157. void UIDocument::loadFromMemory(const char *mem, int size)
  158. {
  159. xmlDocPtr doc = xmlParseMemory (const_cast<char *> (mem), size);
  160. if (!doc || !doc->root || !doc->root->name)
  161. {
  162. error("Error: corrupted XML in file");
  163. addNetwork("MAIN", UINetwork::subnet);
  164. resetModified();
  165. return;
  166. }
  167. xmlNodePtr root=doc->root;
  168. loadXML(root);
  169. xmlFreeDoc(doc);
  170. }
  171. void UIDocument::loadXML(xmlNodePtr root)
  172. {
  173. //loadAllSubnetInfo(root->childs);
  174. subnetInfo.clean();
  175. subnetInfo.loadAllSubnetInfo(root->childs);
  176. xmlNodePtr net = root->childs;
  177. //cerr << "parsing...\n";
  178. while (net != NULL)
  179. {
  180. //cerr << "start net\n";
  181. if (string((char*)net->name) == "Network")
  182. addNetwork (net);
  183. net = net->next;
  184. }
  185. vector<ItemInfo *> tmp = getNetParams("MAIN");
  186. //cerr << "Got " << tmp.size() << " params in GUIDocument::createParamDialog\n";
  187. //textParams.resize(tmp.size());
  188. for (unsigned int i=0;i<tmp.size();i++)
  189. {
  190. DocParameterDataText *newParam = new DocParameterDataText;
  191. newParam->name = string (tmp[i]->name);
  192. textParams.insert(textParams.end(), newParam);
  193. //textParams[i]->name=tmp[i];
  194. }
  195. //cerr << "--\n";
  196. xmlNodePtr par = root->childs;
  197. //cerr << "par = " << par << endl;
  198. while (par)
  199. {
  200. if (string((char*)par->name) == "Parameter")
  201. {
  202. char *str_name = (char *) xmlGetProp(par, (CHAR *)"name");
  203. char *str_type = (char *) xmlGetProp(par, (CHAR *)"type");
  204. char *str_value = (char *) xmlGetProp(par, (CHAR *)"value");
  205. string name = string (str_name);
  206. string type = string (str_type);
  207. string value = string (str_value);
  208. free(str_name); free(str_type); free(str_value);
  209. for (unsigned int i=0;i<textParams.size();i++)
  210. {
  211. if (textParams[i]->name == name)
  212. {
  213. textParams[i]->type = type;
  214. textParams[i]->value = value;
  215. //insertLoadedParam(param, type, value);
  216. }
  217. }
  218. //cerr << "<param: " << name << ", " << type << ":" << value << ">\n";
  219. }
  220. par = par->next;
  221. }
  222. modified = false;
  223. }
  224. UINetwork *UIDocument::newNetwork(const string &_name, UINetwork::Type type)
  225. {
  226. //cerr << "UIDocument::newNetwork\n";
  227. return new UINetwork(this, _name, type);
  228. }
  229. UINetwork *UIDocument::newNetwork(xmlNodePtr _net)
  230. {
  231. //cerr << "UIDocument::newNetwork\n";
  232. return new UINetwork(this, _net);
  233. }
  234. UINetwork *UIDocument::addNetwork(string name, UINetwork::Type type)
  235. {
  236. //cerr << "UIDocument::addNetwork (type = " << typeid(this).name() << ")" << endl;
  237. //UINetwork *newNet = new GUINetwork(this, name, iter);
  238. bool found = false;
  239. for (unsigned int i = 0; i < networks.size(); i++) {
  240. if (networks[i]->getName() == name) {
  241. found = true;
  242. break;
  243. }
  244. }
  245. if (found) {
  246. throw new GeneralException(string("Network already exist : ") + string(name), __FILE__, __LINE__);
  247. }
  248. UINetwork *newNet = newNetwork(name, type);
  249. for (unsigned int i=0;i<networks.size();i++)
  250. {
  251. networks[i]->newNetNotify("Subnet",name);
  252. newNet->newNetNotify("Subnet",networks[i]->getName());
  253. }
  254. networks.insert(networks.end(), newNet);
  255. modified = true;
  256. return newNet;
  257. }
  258. UINetwork *UIDocument::addNetwork(xmlNodePtr xmlNet)
  259. {
  260. //cerr << "creating...\n";
  261. UINetwork *newNet = newNetwork(xmlNet);
  262. //cerr << "created\n";
  263. //cerr << "newNet = " << newNet << endl;
  264. //cerr << "network created in UIDocument::addNetwork\n";
  265. for (unsigned int i=0;i<networks.size();i++)
  266. {
  267. networks[i]->newNetNotify("Subnet",newNet->getName());
  268. newNet->newNetNotify("Subnet",networks[i]->getName());
  269. }
  270. //cerr << "newNet = " << newNet << endl;
  271. networks.insert(networks.end(), newNet);
  272. modified = true;
  273. return newNet;
  274. }
  275. //This function looks useless. Is it?
  276. void UIDocument::removeNetwork(UINetwork *toRemove)
  277. {
  278. vector<UINetwork *>::iterator i=networks.begin();
  279. while (i != networks.end())
  280. {
  281. if (*i == toRemove)
  282. {
  283. delete (*i);
  284. networks.erase(i);
  285. break;
  286. }
  287. ++i;
  288. }
  289. setModified();
  290. }
  291. void UIDocument::error(char *err)
  292. {
  293. cerr << err << endl;
  294. }
  295. void UIDocument::save()
  296. {
  297. string fullname = path+docName;
  298. int size;
  299. int save_fd = open(fullname.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 00755);
  300. if (save_fd==-1)
  301. {
  302. error("Error while saving file: cannot open");
  303. return;
  304. }
  305. fd_ostream outFile(save_fd);
  306. if (outFile.fail())
  307. {
  308. error("Error while saving file");
  309. return;
  310. }
  311. char *mem = saveToMemory(size);
  312. outFile << "#!/usr/bin/env batchflow" << endl;
  313. outFile.write(mem, size);
  314. if (outFile.fail())
  315. {
  316. free(mem);
  317. error("Error while saving file");
  318. return;
  319. }
  320. free(mem);
  321. resetModified();
  322. }
  323. char *UIDocument::saveToMemory(int &size)
  324. {
  325. xmlDocPtr doc;
  326. doc = xmlNewDoc((CHAR *)"1.0");
  327. doc->root = xmlNewDocNode(doc, NULL, (CHAR *)"Document", NULL);
  328. for (unsigned int i=0;i<networks.size();i++)
  329. {
  330. networks[i]->saveXML(doc->root);
  331. }
  332. for (unsigned int i=0;i<textParams.size();i++)
  333. {
  334. xmlNodePtr tree;
  335. tree = xmlNewChild(doc->root, NULL, (CHAR *)"Parameter", NULL);
  336. xmlSetProp(tree, (CHAR *)"name", (CHAR *)textParams[i]->name.c_str());
  337. xmlSetProp(tree, (CHAR *)"type", (CHAR *)textParams[i]->type.c_str());
  338. xmlSetProp(tree, (CHAR *)"value", (CHAR *)textParams[i]->value.c_str());
  339. }
  340. char *mem;
  341. xmlDocDumpMemory(doc,(CHAR **)&mem,&size);
  342. xmlFreeDoc(doc);
  343. return mem;
  344. }
  345. string UIDocument::findExternal(const string &filename, char *searchPath, bool include_home, bool fullPathOutput)
  346. {
  347. vector<string> pathlist = envList(searchPath, include_home);
  348. string fullname;
  349. for (unsigned int i=0;i<pathlist.size();i++)
  350. {
  351. if (findExternalRecursive(pathlist[i],"", filename,fullname, fullPathOutput))
  352. return fullname;
  353. }
  354. return "";
  355. }
  356. bool UIDocument::findExternalRecursive(const string &basePath, const string &path, const string &filename, string &fullname, bool fullPathOutput)
  357. {
  358. struct stat my_stat;
  359. string dirPath = basePath + "/" + path;
  360. DIR *my_directory = opendir (dirPath.c_str());
  361. if (!my_directory) return false;
  362. struct dirent *current_entry;
  363. for (current_entry = readdir(my_directory);
  364. current_entry != NULL; current_entry = readdir(my_directory)) {
  365. string name = current_entry->d_name;
  366. string fullpath = basePath + "/" + path + string("/") + name;
  367. if (stat(fullpath.c_str(), &my_stat) < 0) {
  368. //cerr<<"stat error"<<endl;
  369. perror(fullpath.c_str());
  370. continue;
  371. }
  372. if (S_ISDIR(my_stat.st_mode)) {
  373. //it is a directory, let's doing it recursively
  374. if (name != string("..") && name != string(".")) {
  375. if (findExternalRecursive(basePath, path + "/" + name,filename,fullname, fullPathOutput))
  376. {
  377. closedir(my_directory);
  378. return true;
  379. }
  380. }
  381. }
  382. else {
  383. //it's a file, check if it's the right one
  384. if (name == filename) {
  385. if (fullPathOutput)
  386. fullname = fullpath;
  387. else
  388. fullname = path + string("/") + name;
  389. closedir(my_directory);
  390. return true;
  391. }
  392. }
  393. }
  394. closedir(my_directory);
  395. return false;
  396. }
  397. Network *UIDocument::buildExternal(const string &type, const string &_name, const ParameterSet &params)
  398. {
  399. string fullname = findExternal(type + ".n");
  400. if (fullname == "")
  401. return NULL;
  402. UIDocument doc(fullname);
  403. //cout<<"loading : "<<fullpath<<endl;
  404. doc.load();
  405. UINetwork *net = doc.getNetworkNamed("MAIN");
  406. if (net)
  407. return net->build(_name, params);
  408. else
  409. throw new GeneralException("No MAIN network defined", __FILE__, __LINE__);
  410. }
  411. Network *UIDocument::build(const string &_name, const ParameterSet &params)
  412. {
  413. Network *net = NULL;
  414. try {
  415. UINetwork *uinet = getNetworkNamed("MAIN");
  416. if (!uinet)
  417. throw new GeneralException("No MAIN network defined", __FILE__, __LINE__);
  418. net = uinet->build(_name, params);
  419. net->verifyConnect();
  420. return net;
  421. } catch (BaseException *e)
  422. {
  423. e->freeze();
  424. if (net)
  425. {
  426. net->cleanupNotify();
  427. delete net;
  428. }
  429. throw e;
  430. } catch (...)
  431. {
  432. if (net)
  433. {
  434. net->cleanupNotify();
  435. delete net;
  436. }
  437. throw;
  438. }
  439. }
  440. void UIDocument::genCodeExternal(const string &type, ostream &out, int &id, set<string> &nodeList)
  441. {
  442. string fullname = findExternal(type+".n");
  443. if (fullname == "")
  444. throw new GeneralException(string("External node not found: ") + type, __FILE__, __LINE__);
  445. UIDocument doc(fullname);
  446. doc.load();
  447. UINetwork *uinet = doc.getNetworkNamed("MAIN");
  448. if (!uinet)
  449. throw new GeneralException("No MAIN network defined", __FILE__, __LINE__);
  450. uinet->genCode(out, id, nodeList);
  451. }
  452. set<string> UIDocument::genCode(ostream &out, const string &functName, bool localIncludes)
  453. {
  454. set<string> nodeList;
  455. out << "//This code has been generated automatically using codeflow\n";
  456. out << "//Note that automatic code generation is in a very experimental\n";
  457. out << "// stage right now, use at your own risk\n";
  458. if (localIncludes)
  459. {
  460. out << "#include \"Network.h\"\n";
  461. out << "#include \"Iterator.h\"\n";
  462. out << "#include \"object_param.h\"\n\n\n";
  463. } else {
  464. out << "#include <Network.h>\n";
  465. out << "#include <Iterator.h>\n";
  466. out << "#include <object_param.h>\n\n\n";
  467. }
  468. int id=0;
  469. UINetwork *uinet = getNetworkNamed("MAIN");
  470. if (!uinet)
  471. throw new GeneralException("No MAIN network defined", __FILE__, __LINE__);
  472. uinet->genCode(out, id, nodeList);
  473. out << "Network *" << functName << "(const string &_name, ParameterSet &params)" << endl;
  474. out << "{\n";
  475. out << "\tNetwork *net = genNet0(_name, params);\n";
  476. //Don't verify... in case we need other connections
  477. //out << "\tnet->verifyConnect();\n";
  478. out << "\treturn net;\n";
  479. out << "}\n";
  480. //cerr << "nodes used:\n";
  481. //for (set<string>::iterator it=nodeList.begin();it!=nodeList.end();it++)
  482. // cerr << *it << endl;
  483. return nodeList;
  484. }
  485. //Run without a GUI
  486. void UIDocument::run()
  487. {
  488. Network *net = NULL;
  489. try {
  490. ParameterSet params;
  491. //cerr << "building net...\n";
  492. net = build("MAIN", params);
  493. if (net->getInputNode())
  494. throw new GeneralException ("main network has input node", __FILE__, __LINE__);
  495. //cerr << "initializing...\n";
  496. net->initialize();
  497. //cerr << "running (UIDocument)...\n";
  498. for (int i = 0; ;i++) {
  499. if (!net->hasOutput(i)) break;
  500. cout << *net->getOutput(i,0);
  501. }
  502. } catch (BaseException *e)
  503. {
  504. e->print();
  505. } catch (...)
  506. {
  507. cerr << "unknown exception caught" << endl;
  508. }
  509. if (net)
  510. {
  511. net->cleanupNotify();
  512. delete net;
  513. }
  514. }
  515. void UIDocument::run(ParameterSet &p)
  516. {
  517. Network *net=NULL;
  518. try {
  519. //cerr << "building net...\n";
  520. net = build("MAIN", p);
  521. if (net->getInputNode())
  522. throw new GeneralException ("main network has input node", __FILE__, __LINE__);
  523. //cerr << "initializing...\n";
  524. net->initialize();
  525. //cerr << "running (UIDocument)...\n";
  526. for (int i = 0; ;i++)
  527. {
  528. if (!net->hasOutput(i))
  529. break;
  530. *net->getOutput(i,0);
  531. }
  532. }
  533. catch (BaseException &e) {
  534. e.print();
  535. }
  536. catch (BaseException *e)
  537. {
  538. e->print();
  539. }
  540. if (net)
  541. {
  542. net->cleanupNotify();
  543. delete net;
  544. }
  545. }
  546. void UIDocument::setFullPath(const string &fullpath)
  547. {
  548. //cerr << "fullpath is: \"" << fullpath << "\"" << endl;
  549. int slashpos = fullpath.rfind("/");
  550. //cerr << "slashpos = " << slashpos << endl;
  551. path="";
  552. path.append(fullpath,0,slashpos+1);
  553. docName=fullpath;
  554. docName.erase(0,slashpos+1);
  555. //cerr << "path is: \"" << path << "\"" << endl;
  556. //cerr << "name is: \"" << name << "\"" << endl;
  557. untitled=false;
  558. }
  559. void UIDocument::updateAllNetworks() {
  560. //update network information
  561. for (int i=0;i<networks.size();i++)
  562. subnetInfo.updateNetInfo(networks[i]);
  563. }