plib.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file plib.cpp
  3. /// \brief PLIB Version 2.1 (Fully portable version)
  4. ///
  5. /// Documentation: see header file plib.h
  6. ///
  7. /// Enquiries to: Joe Siltberg, Lund University: joe.siltberg@nateko.lu.se
  8. /// All rights reserved, copyright retained by the author.
  9. ///
  10. /// \author Ben Smith, University of Lund
  11. /// $Date: 2013-09-03 11:06:34 +0200 (Tue, 03 Sep 2013) $
  12. #include "plib.h"
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <time.h>
  16. #include <string.h>
  17. #include <gutil.h>
  18. #include "recursivefilereader.h"
  19. enum itemtype {PLIB_XTRING,PLIB_STDSTRING,PLIB_INT,PLIB_DOUBLE,PLIB_SET,
  20. PLIB_BOOLEAN,PLIB_FLAG};
  21. enum wordtype {WORD_IDENTIFIER,WORD_STRING,WORD_NUMBER,WORD_OPENPARENTHESIS,
  22. WORD_CLOSEPARENTHESIS,WORD_GROUP,WORD_NOWORD};
  23. enum errortype {PLIB_NOERROR,PLIB_INVALIDNUMBER,PLIB_OUTOFMEMORY,PLIB_ENDOFFILE,
  24. PLIB_PARENTHESISNESTING,PLIB_GROUPHEADER,PLIB_DUPLICATEGROUPNAME,PLIB_FILEOPEN,
  25. PLIB_EXPECTIDENTIFIER,PLIB_UNDEFINEDITEM,PLIB_EXPECTSTRING,PLIB_EXPECTNUMBER,
  26. PLIB_OUTOFRANGE,PLIB_EXPECTOPENPARENTHESIS,PLIB_ABORT,PLIB_UNRECOGNISEDTOKEN};
  27. struct Plibitem {
  28. itemtype type;
  29. xtring identifier;
  30. void* param;
  31. double min;
  32. double max;
  33. union {
  34. int nparam;
  35. int maxlen;
  36. int id;
  37. };
  38. int callback;
  39. bool called;
  40. };
  41. class Pliblist {
  42. public:
  43. int callback;
  44. struct itemkey {
  45. Plibitem* pitem;
  46. itemkey* pprev;
  47. itemkey* pnext;
  48. };
  49. private:
  50. itemkey* m_pfirst;
  51. itemkey* m_pthis;
  52. public:
  53. Pliblist();
  54. bool addtostart(Plibitem& pitem);
  55. Plibitem* getfirstitem();
  56. Plibitem* getnextitem();
  57. void removeitem();
  58. };
  59. struct Plibword {
  60. wordtype type;
  61. xtring string;
  62. union {
  63. double num;
  64. Plibword* pgroup;
  65. };
  66. xtring filename;
  67. int lineno;
  68. Plibword* pnext;
  69. };
  70. struct Plibgroup {
  71. xtring name;
  72. Plibword* pfirst;
  73. Plibgroup* pnext;
  74. };
  75. static const int MAXWORD=499;
  76. // maximum number of characters (excluding terminating \0) for a word in script file
  77. static Pliblist* pthislist;
  78. static char currch;
  79. static xtring lastfile;
  80. static xtring lastword;
  81. static int lastline=0;
  82. static bool ishelp=false; // true if call is to function plibhelp, otherwise false
  83. static bool abortparse=false;
  84. Pliblist::Pliblist() {
  85. m_pfirst=m_pthis=NULL;
  86. }
  87. bool Pliblist::addtostart(Plibitem& pitem) {
  88. itemkey* ik;
  89. ik=new itemkey;
  90. if (!ik) return false;
  91. ik->pitem=new Plibitem;
  92. if (!ik->pitem) return false;
  93. *(ik->pitem)=pitem;
  94. ik->pnext=m_pfirst;
  95. ik->pprev=NULL;
  96. if (m_pfirst) m_pfirst->pprev=ik;
  97. m_pfirst=ik;
  98. m_pthis=ik;
  99. return true;
  100. }
  101. Plibitem* Pliblist::getfirstitem() {
  102. if (!m_pfirst) return NULL;
  103. m_pthis=m_pfirst;
  104. return m_pthis->pitem;
  105. }
  106. Plibitem* Pliblist::getnextitem() {
  107. if (!m_pthis) return NULL;
  108. m_pthis=m_pthis->pnext;
  109. if (!m_pthis) return NULL;
  110. return m_pthis->pitem;
  111. }
  112. void Pliblist::removeitem() {
  113. if (!m_pthis) return;
  114. if (m_pthis->pnext) m_pthis->pnext->pprev=m_pthis->pprev;
  115. if (m_pthis->pprev) m_pthis->pprev->pnext=m_pthis->pnext;
  116. if (m_pthis==m_pfirst) m_pfirst=m_pthis->pnext;
  117. delete m_pthis->pitem;
  118. delete m_pthis;
  119. m_pthis=NULL;
  120. }
  121. void helpheader(char* blockname) {
  122. // Called by helpout and block header overload of declareitem to output
  123. // header string for help text for block with specified name
  124. xtring output=(xtring)"\nKeywords defined within block \""+blockname+"\":\n\n";
  125. plib_receivemessage(output);
  126. }
  127. void helpout(xtring& identifier, xtring& help) {
  128. // Called by declareitem to output help text if requested (by a call to plibhelp)
  129. const char* TAB = "\n ";
  130. xtring output;
  131. output.printf("%-15s", (char*)identifier);
  132. output += identifier.len() > 15 ? TAB : " ";
  133. xtring helpcpy = "(no help available)";
  134. if (*help) {
  135. const int MAXHELPSTRING = 63;
  136. helpcpy = help.left(MAXHELPSTRING);
  137. div_t q = div(help.len(), MAXHELPSTRING);
  138. for (int l=1; l < (q.quot + int(q.rem > 0)); l++) {
  139. helpcpy += TAB;
  140. helpcpy += help.mid(l * MAXHELPSTRING, MAXHELPSTRING);
  141. }
  142. }
  143. plib_receivemessage(output + helpcpy + "\n");
  144. }
  145. bool declareitem(xtring identifier,xtring* param,int maxlen,int callback,xtring help) {
  146. // String with specified maximum length
  147. // e.g. title 'kiruna 20 67.5'
  148. Plibitem item;
  149. if (ishelp) helpout(identifier,help);
  150. else {
  151. item.identifier=identifier.lower();
  152. item.type=PLIB_XTRING;
  153. item.param=param;
  154. item.maxlen=maxlen;
  155. item.callback=callback;
  156. item.called=false;
  157. if (!pthislist->addtostart(item)) return false;
  158. }
  159. return true;
  160. }
  161. bool declareitem(xtring identifier, std::string* param, int maxlen, int callback, xtring help) {
  162. // String with specified maximum length
  163. // e.g. title 'kiruna 20 67.5'
  164. Plibitem item;
  165. if (ishelp) helpout(identifier,help);
  166. else {
  167. item.identifier=identifier.lower();
  168. item.type=PLIB_STDSTRING;
  169. item.param=param;
  170. item.maxlen=maxlen;
  171. item.callback=callback;
  172. item.called=false;
  173. if (!pthislist->addtostart(item)) return false;
  174. }
  175. return true;
  176. }
  177. bool declareitem(xtring identifier,int* param,int min,int max,int nparam,
  178. int callback,xtring help) {
  179. // Integer(s) in specified range
  180. // e.g. npat 10
  181. Plibitem item;
  182. if (ishelp) helpout(identifier,help);
  183. else {
  184. item.identifier=identifier.lower();
  185. item.type=PLIB_INT;
  186. item.param=param;
  187. item.min=min;
  188. item.max=max;
  189. item.nparam=nparam;
  190. item.callback=callback;
  191. item.called=false;
  192. if (!pthislist->addtostart(item)) return false;
  193. }
  194. return true;
  195. }
  196. bool declareitem(xtring identifier,double* param,double min,double max,
  197. int nparam,int callback,xtring help) {
  198. // Double(s) in specified range
  199. // e.g. soilawc 55 110
  200. Plibitem item;
  201. if (ishelp) helpout(identifier,help);
  202. else {
  203. item.identifier=identifier.lower();
  204. item.type=PLIB_DOUBLE;
  205. item.param=param;
  206. item.min=min;
  207. item.max=max;
  208. item.nparam=nparam;
  209. item.callback=callback;
  210. item.called=false;
  211. if (!pthislist->addtostart(item)) return false;
  212. }
  213. return true;
  214. }
  215. bool declareitem(xtring identifier,bool* param,int nparam,int callback,xtring help) {
  216. // Boolean(s) with parameter
  217. // e.g. include 1
  218. Plibitem item;
  219. if (ishelp) helpout(identifier,help);
  220. else {
  221. item.identifier=identifier.lower();
  222. item.type=PLIB_BOOLEAN;
  223. item.param=param;
  224. item.nparam=nparam;
  225. item.callback=callback;
  226. item.called=false;
  227. if (!pthislist->addtostart(item)) return false;
  228. }
  229. return true;
  230. }
  231. bool declareitem(xtring identifier,bool* param,int callback,xtring help) {
  232. // Boolean without parameter (flag)
  233. // e.g. anpp
  234. Plibitem item;
  235. if (ishelp) helpout(identifier,help);
  236. else {
  237. item.identifier=identifier.lower();
  238. item.type=PLIB_FLAG;
  239. item.param=param;
  240. item.callback=callback;
  241. item.called=false;
  242. if (!pthislist->addtostart(item)) return false;
  243. }
  244. return true;
  245. }
  246. bool declareitem(xtring identifier,int id,int callback,xtring help) {
  247. // Block heading
  248. // e.g. taxon "picea" (
  249. Plibitem item;
  250. if (ishelp) {
  251. helpout(identifier,help);
  252. helpheader(identifier);
  253. plib_declarations(id,"");
  254. }
  255. else {
  256. item.identifier=identifier.lower();
  257. item.type=PLIB_SET;
  258. item.id=id;
  259. item.callback=callback;
  260. item.called=false;
  261. if (!pthislist->addtostart(item)) return false;
  262. }
  263. return true;
  264. }
  265. void callwhendone(int callback) {
  266. if (!ishelp) pthislist->callback=callback;
  267. }
  268. void nextch(RecursiveFileReader& in) {
  269. // Gets next 'valid' character on in
  270. // Ignored non-printable characters (<32, except \n)
  271. if (in.Feof()) {
  272. currch=' ';
  273. return;
  274. }
  275. do {
  276. currch=in.Fgetc();
  277. } while (currch<' ' && currch!='\n' && !in.Feof());
  278. if (in.Feof()) currch=' ';
  279. }
  280. void readto(xtring& string,char* termlist,RecursiveFileReader& in) {
  281. // Reads sequential characters on stream in up to first instance of one of
  282. // the characters in termlist, returning resultant string in string
  283. char* termptr;
  284. bool term=false;
  285. int len=0;
  286. do {
  287. termptr=termlist;
  288. while (*termptr)
  289. if (currch==*termptr++) term=true;
  290. if (in.Feof()) term=true;
  291. if (!term && len<MAXWORD) string[len++]=currch;
  292. if (!term) nextch(in);
  293. } while (!term);
  294. string[len]=0;
  295. lastword=string;
  296. }
  297. void getnextword(Plibword& plibword,RecursiveFileReader& in,errortype& err) {
  298. bool iscomment=false;
  299. xtring string;
  300. do {
  301. iscomment=false;
  302. if (!currch) nextch(in);
  303. while ((currch==' ' || currch=='\t' || currch=='\n') && !in.Feof()) nextch(in);
  304. if (in.Feof()) { // end of file
  305. plibword.type=WORD_NOWORD;
  306. plibword.lineno = 0;
  307. plibword.filename = "";
  308. err=PLIB_NOERROR; //PLIB_ENDOFFILE;
  309. return;
  310. }
  311. else {
  312. plibword.lineno = in.currentlineno();
  313. plibword.filename = in.currentfilename();
  314. }
  315. if ((currch>='a' && currch<='z') || (currch>='A' && currch<='Z')) { // identifier
  316. char termlist[]=" \t\n-+.\"\'()!";
  317. readto(string,termlist,in);
  318. plibword.string=string.lower();
  319. plibword.type=WORD_IDENTIFIER;
  320. }
  321. else if (currch=='\'' || currch=='\"') { // string
  322. xtring termlist=currch;
  323. nextch(in);
  324. readto(string,termlist,in);
  325. plibword.string=string;
  326. plibword.type=WORD_STRING;
  327. nextch(in);
  328. }
  329. else if (currch=='-' || currch=='+' || (currch>='0' && currch<='9') || currch=='.') { // number
  330. char termlist[]=" \t\n\"\'()!";
  331. readto(string,termlist,in);
  332. if (!string.isnum()) {
  333. err=PLIB_INVALIDNUMBER;
  334. return;
  335. }
  336. plibword.string=string;
  337. plibword.num=string.num();
  338. plibword.type=WORD_NUMBER;
  339. }
  340. else if (currch=='(') { // open parenthesis
  341. plibword.type=WORD_OPENPARENTHESIS;
  342. plibword.string="(";
  343. nextch(in);
  344. }
  345. else if (currch==')') { // close parenthesis
  346. plibword.type=WORD_CLOSEPARENTHESIS;
  347. plibword.string=")";
  348. nextch(in);
  349. }
  350. else if (currch=='!') { // comment
  351. nextch(in);
  352. while (currch!='\n' && !in.Feof()) nextch(in);
  353. iscomment=true;
  354. }
  355. else {
  356. err=PLIB_UNRECOGNISEDTOKEN;
  357. return;
  358. }
  359. } while (iscomment);
  360. err=PLIB_NOERROR;
  361. }
  362. bool findgroup(Plibgroup* pfirstgroup,xtring& name,Plibgroup& plibgroup) {
  363. // Looks for group with specified name
  364. // Returns false if group not in list
  365. Plibgroup* pgroup=pfirstgroup;
  366. while (pgroup) {
  367. if (pgroup->name==name) {
  368. plibgroup=*pgroup;
  369. return true;
  370. }
  371. pgroup=pgroup->pnext;
  372. }
  373. return false;
  374. }
  375. void loadscript(RecursiveFileReader& in,Plibword*& pfirstword,errortype& err,bool isgroup,
  376. Plibgroup*& pfirstgroup,bool& firstgroup,Plibgroup*& plastgroup,
  377. Plibword& plibword) {
  378. Plibword* pword;
  379. Plibword* pthisword;
  380. bool firstword=true;
  381. bool groupheader=false;
  382. bool waitgroupname=false;
  383. bool importstatement=false;
  384. bool addword;
  385. Plibgroup plibgroup;
  386. //Plibgroup* pthisgroup;
  387. Plibgroup* pgroup;
  388. int parct=0;
  389. while (!in.Feof()) {
  390. getnextword(plibword,in,err);
  391. lastfile = plibword.filename;
  392. lastword=plibword.string;
  393. lastline=plibword.lineno;
  394. if (err) return;
  395. else {
  396. addword=true;
  397. if (groupheader) {
  398. if (waitgroupname) {
  399. if (plibword.type!=WORD_STRING) {
  400. err=PLIB_GROUPHEADER;
  401. return;
  402. }
  403. plibword.string=plibword.string.lower();
  404. if (findgroup(pfirstgroup,plibword.string,plibgroup)) {
  405. err=PLIB_DUPLICATEGROUPNAME;
  406. return;
  407. }
  408. plibgroup.name=plibword.string;
  409. waitgroupname=false;
  410. }
  411. else { // waiting for open parenthesis
  412. if (plibword.type!=WORD_OPENPARENTHESIS) {
  413. err=PLIB_GROUPHEADER;
  414. return;
  415. }
  416. //parct++;
  417. // Load group
  418. plibgroup.pfirst=NULL;
  419. loadscript(in,plibgroup.pfirst,err,true,pfirstgroup,firstgroup,
  420. plastgroup,plibword);
  421. if (err) return;
  422. plibgroup.pnext=NULL;
  423. pgroup=new Plibgroup;
  424. if (!pgroup) {
  425. err=PLIB_OUTOFMEMORY;
  426. return;
  427. }
  428. *pgroup=plibgroup;
  429. if (firstgroup) {
  430. pfirstgroup=pgroup;
  431. firstgroup=false;
  432. plastgroup=pfirstgroup;
  433. }
  434. else {
  435. plastgroup->pnext=pgroup;
  436. plastgroup=pgroup;
  437. }
  438. //pthisgroup=pgroup;
  439. groupheader=false;
  440. waitgroupname=false;
  441. }
  442. addword=false;
  443. }
  444. else if (importstatement) {
  445. importstatement = false;
  446. addword = false;
  447. if (plibword.type != WORD_STRING) {
  448. err = PLIB_EXPECTSTRING;
  449. return;
  450. }
  451. else if (!in.addfile(plibword.string)) {
  452. err = PLIB_FILEOPEN;
  453. return;
  454. }
  455. }
  456. else if (plibword.type==WORD_CLOSEPARENTHESIS) {
  457. if (parct) parct--;
  458. else {
  459. if (isgroup) return; // end of group block
  460. // else
  461. err=PLIB_PARENTHESISNESTING;
  462. return;
  463. }
  464. }
  465. else if (plibword.type==WORD_OPENPARENTHESIS)
  466. parct++;
  467. else if (plibword.type==WORD_IDENTIFIER) {
  468. if (plibword.string==(char*)"group") {
  469. groupheader=true;
  470. waitgroupname=true;
  471. addword=false;
  472. }
  473. else if (plibword.string == "import") {
  474. importstatement = true;
  475. addword = false;
  476. }
  477. else {
  478. // Check if this is a call to a group
  479. if (findgroup(pfirstgroup,plibword.string,plibgroup)) {
  480. plibword.pgroup=plibgroup.pfirst;
  481. plibword.type=WORD_GROUP;
  482. }
  483. }
  484. }
  485. else if (plibword.type==WORD_NOWORD) {
  486. addword=false;
  487. }
  488. if (addword) {
  489. plibword.pnext=NULL;
  490. pword=new Plibword;
  491. if (!pword) {
  492. err=PLIB_OUTOFMEMORY;
  493. return;
  494. }
  495. *pword=plibword;
  496. if (firstword) {
  497. pfirstword=pword;
  498. firstword=false;
  499. }
  500. else {
  501. pthisword->pnext=pword;
  502. }
  503. pthisword=pword;
  504. }
  505. }
  506. }
  507. err=PLIB_NOERROR;
  508. return;
  509. }
  510. void findidentifier(Pliblist& pliblist,xtring& identifier,Plibitem*& pitem) {
  511. // Looks for a plib item with specified identifier in pliblist,
  512. // returning pointer to item (or NULL if item is not found)
  513. pitem=pliblist.getfirstitem();
  514. while (pitem) {
  515. if (pitem->identifier==identifier) return;
  516. pitem=pliblist.getnextitem();
  517. }
  518. pitem=NULL;
  519. }
  520. bool itemparsed(xtring identifier) {
  521. Plibitem* pitem;
  522. xtring string=identifier.lower();
  523. findidentifier(*pthislist,string,pitem);
  524. if (!pitem) return false;
  525. return pitem->called;
  526. }
  527. void killpliblist(Pliblist* plist) {
  528. Plibitem* pitem;
  529. pitem=plist->getfirstitem();
  530. while (pitem) {
  531. plist->removeitem();
  532. pitem=plist->getfirstitem();
  533. }
  534. }
  535. Plibword* parse_plib_script(int id,xtring setname,errortype& err,Plibword* pfirstword,
  536. bool newset,Pliblist* plist) {
  537. Pliblist pliblist;
  538. Plibword* pword=pfirstword,*pgroupword;
  539. Plibitem* pitem;
  540. pthislist=&pliblist;
  541. if (newset) {
  542. pliblist.callback=0;
  543. plib_declarations(id,setname);
  544. plist=&pliblist;
  545. if (abortparse) {
  546. killpliblist(&pliblist);
  547. err=PLIB_ABORT;
  548. return pword;
  549. }
  550. }
  551. int i;
  552. while (pword) {
  553. lastword=pword->string;
  554. lastline=pword->lineno;
  555. lastfile=pword->filename;
  556. if (pword->type==WORD_GROUP) {
  557. pgroupword=parse_plib_script(id,"",err,pword->pgroup,false,plist);
  558. if (err) {
  559. killpliblist(&pliblist);
  560. return pgroupword;
  561. }
  562. }
  563. else if (pword->type==WORD_CLOSEPARENTHESIS) {
  564. if (!id) err=PLIB_PARENTHESISNESTING;
  565. else err=PLIB_NOERROR;
  566. pthislist=plist;
  567. if (plist->callback && newset) {
  568. plib_callback(plist->callback);
  569. if (abortparse) {
  570. err=PLIB_ABORT;
  571. }
  572. }
  573. killpliblist(&pliblist);
  574. return pword;
  575. }
  576. else if (pword->type!=WORD_IDENTIFIER) {
  577. err=PLIB_EXPECTIDENTIFIER;
  578. killpliblist(&pliblist);
  579. return pword;
  580. }
  581. else {
  582. findidentifier(*plist,pword->string,pitem);
  583. if (!pitem) {
  584. err=PLIB_UNDEFINEDITEM;
  585. killpliblist(&pliblist);
  586. return pword;
  587. }
  588. // Now pitem points to item to assign to
  589. switch (pitem->type) {
  590. case PLIB_XTRING:
  591. case PLIB_STDSTRING:
  592. pword=pword->pnext;
  593. lastword=pword->string;
  594. lastline=pword->lineno;
  595. if (!pword) {
  596. err=PLIB_ENDOFFILE;
  597. killpliblist(&pliblist);
  598. return pword;
  599. }
  600. if (pword->type!=WORD_STRING) {
  601. err=PLIB_EXPECTSTRING;
  602. killpliblist(&pliblist);
  603. return pword;
  604. }
  605. if (static_cast<int>(pword->string.len())>pitem->maxlen-1)
  606. pword->string=pword->string.left(pitem->maxlen-1);
  607. if (pitem->type == PLIB_XTRING) {
  608. *((xtring*)(pitem->param))=pword->string;
  609. }
  610. else {
  611. *((std::string*)(pitem->param))=pword->string;
  612. }
  613. pitem->called=true;
  614. break;
  615. case PLIB_INT:
  616. for (i=0;i<pitem->nparam;i++) {
  617. pword=pword->pnext;
  618. lastword=pword->string;
  619. lastline=pword->lineno;
  620. if (!pword) {
  621. err=PLIB_ENDOFFILE;
  622. killpliblist(&pliblist);
  623. return pword;
  624. }
  625. if (pword->type!=WORD_NUMBER) {
  626. err=PLIB_EXPECTNUMBER;
  627. killpliblist(&pliblist);
  628. return pword;
  629. }
  630. if (pword->num<pitem->min || pword->num>pitem->max) {
  631. err=PLIB_OUTOFRANGE;
  632. killpliblist(&pliblist);
  633. return pword;
  634. }
  635. *((int*)(pitem->param)+i)=(int)(pword->num+0.5);
  636. }
  637. pitem->called=true;
  638. break;
  639. case PLIB_DOUBLE:
  640. for (i=0;i<pitem->nparam;i++) {
  641. pword=pword->pnext;
  642. lastword=pword->string;
  643. lastline=pword->lineno;
  644. if (!pword) {
  645. err=PLIB_ENDOFFILE;
  646. killpliblist(&pliblist);
  647. return pword;
  648. }
  649. if (pword->type!=WORD_NUMBER) {
  650. err=PLIB_EXPECTNUMBER;
  651. killpliblist(&pliblist);
  652. return pword;
  653. }
  654. if (pword->num<pitem->min || pword->num>pitem->max) {
  655. err=PLIB_OUTOFRANGE;
  656. killpliblist(&pliblist);
  657. return pword;
  658. }
  659. *((double*)(pitem->param)+i)=pword->num;
  660. }
  661. pitem->called=true;
  662. break;
  663. case PLIB_BOOLEAN:
  664. for (i=0;i<pitem->nparam;i++) {
  665. pword=pword->pnext;
  666. lastword=pword->string;
  667. lastline=pword->lineno;
  668. if (!pword) {
  669. err=PLIB_ENDOFFILE;
  670. killpliblist(&pliblist);
  671. return pword;
  672. }
  673. if (pword->type!=WORD_NUMBER) {
  674. err=PLIB_EXPECTNUMBER;
  675. killpliblist(&pliblist);
  676. return pword;
  677. }
  678. *((bool*)(pitem->param)+i)=(bool)(!!(pword->num));
  679. }
  680. pitem->called=true;
  681. break;
  682. case PLIB_FLAG:
  683. *(bool*)(pitem->param)=true;
  684. pitem->called=true;
  685. break;
  686. case PLIB_SET:
  687. pword=pword->pnext;
  688. lastword=pword->string;
  689. lastline=pword->lineno;
  690. if (!pword) {
  691. err=PLIB_ENDOFFILE;
  692. killpliblist(&pliblist);
  693. return pword;
  694. }
  695. if (pword->type!=WORD_STRING) {
  696. err=PLIB_EXPECTSTRING;
  697. killpliblist(&pliblist);
  698. return pword;
  699. }
  700. setname=pword->string;
  701. pword=pword->pnext;
  702. lastword=pword->string;
  703. lastline=pword->lineno;
  704. if (!pword) {
  705. err=PLIB_ENDOFFILE;
  706. killpliblist(&pliblist);
  707. return pword;
  708. }
  709. if (pword->type!=WORD_OPENPARENTHESIS) {
  710. err=PLIB_EXPECTOPENPARENTHESIS;
  711. killpliblist(&pliblist);
  712. return pword;
  713. }
  714. pword=pword->pnext;
  715. lastword=pword->string;
  716. lastline=pword->lineno;
  717. pword=parse_plib_script(pitem->id,setname,err,pword,true,NULL);
  718. pitem->called=true;
  719. if (err) {
  720. killpliblist(&pliblist);
  721. return pword;
  722. }
  723. break;
  724. }
  725. if (pitem->callback) {
  726. plib_callback(pitem->callback);
  727. if (abortparse) {
  728. err=PLIB_ABORT;
  729. killpliblist(&pliblist);
  730. return pword;
  731. }
  732. }
  733. }
  734. pword=pword->pnext;
  735. }
  736. if (id && newset) err=PLIB_ENDOFFILE; // should be a close parenthesis
  737. else {
  738. pthislist=plist;
  739. if (plist->callback && newset) plib_callback(plist->callback);
  740. if (abortparse) {
  741. err=PLIB_ABORT;
  742. killpliblist(&pliblist);
  743. return pword;
  744. }
  745. err=PLIB_NOERROR;
  746. }
  747. killpliblist(&pliblist);
  748. return NULL;
  749. }
  750. void getmessageheader(xtring& text) {
  751. text.printf("In %s, line %d, \"%s\":\n",(char*)lastfile,
  752. (char*)lastword,lastline);
  753. }
  754. void sendmessage(xtring heading,xtring message) {
  755. xtring text;
  756. text.printf("In %s, line %d, \"%s\":\n ",(char*)lastfile,lastline,
  757. (char*)lastword);
  758. text+=heading+": "+message+"\n";
  759. plib_receivemessage(text);
  760. }
  761. void geterrormessage(errortype err) {
  762. switch (err) {
  763. case PLIB_INVALIDNUMBER:
  764. sendmessage("Error","Cannot be interpreted as a number");
  765. break;
  766. case PLIB_OUTOFMEMORY:
  767. sendmessage("Error","Out of memory");
  768. break;
  769. case PLIB_ENDOFFILE:
  770. sendmessage("Error","Unexpected end of file");
  771. break;
  772. case PLIB_PARENTHESISNESTING:
  773. sendmessage("Error","Parenthesis nesting error");
  774. break;
  775. case PLIB_GROUPHEADER:
  776. sendmessage("Error","Invalid format for group header");
  777. break;
  778. case PLIB_DUPLICATEGROUPNAME:
  779. sendmessage("Error","Duplicate group name");
  780. break;
  781. case PLIB_FILEOPEN:
  782. sendmessage("Error","Could not open file for input");
  783. break;
  784. case PLIB_EXPECTIDENTIFIER:
  785. sendmessage("Error","Identifier expected");
  786. break;
  787. case PLIB_UNDEFINEDITEM:
  788. sendmessage("Error","Undefined identifier");
  789. break;
  790. case PLIB_EXPECTSTRING:
  791. sendmessage("Error","String expected");
  792. break;
  793. case PLIB_EXPECTNUMBER:
  794. sendmessage("Error","Number expected");
  795. break;
  796. case PLIB_OUTOFRANGE:
  797. sendmessage("Error","Value out of range");
  798. break;
  799. case PLIB_EXPECTOPENPARENTHESIS:
  800. sendmessage("Error","Parenthesis expected");
  801. break;
  802. case PLIB_ABORT:
  803. sendmessage("Error","PLIB forcibly terminated by calling module");
  804. break;
  805. case PLIB_UNRECOGNISEDTOKEN:
  806. sendmessage("Error","Unrecognised token");
  807. case PLIB_NOERROR:
  808. // No nothing (included to avoid warnings from pedantic compilers)
  809. break;
  810. }
  811. }
  812. void plibabort() {
  813. abortparse=true;
  814. };
  815. void killplib(Plibword* pfirstword,Plibgroup* pfirstgroup) {
  816. Plibword* pword,*pthisword;
  817. Plibgroup* pgroup,*pthisgroup;
  818. pword=pfirstword;
  819. while (pword) {
  820. pthisword=pword;
  821. pword=pword->pnext;
  822. delete pthisword;
  823. }
  824. pgroup=pfirstgroup;
  825. while (pgroup) {
  826. pword=pgroup->pfirst;
  827. while (pword) {
  828. pthisword=pword;
  829. pword=pword->pnext;
  830. delete pthisword;
  831. }
  832. pthisgroup=pgroup;
  833. pgroup=pgroup->pnext;
  834. delete pthisgroup;
  835. }
  836. }
  837. bool plib(xtring filename) {
  838. Plibword* pfirstword=NULL;
  839. Plibgroup* pfirstgroup=NULL;
  840. Plibgroup* plastgroup=NULL;
  841. Plibword plibword,*pword;
  842. errortype err;
  843. bool firstgroup=true;
  844. abortparse=false;
  845. lastfile=filename;
  846. lastline=0;
  847. RecursiveFileReader in;
  848. if (!in.addfile(filename)) {
  849. geterrormessage(PLIB_FILEOPEN);
  850. return false;
  851. }
  852. currch='\0';
  853. pfirstgroup=NULL;
  854. loadscript(in,pfirstword,err,false,pfirstgroup,firstgroup,plastgroup,plibword);
  855. if (err) {
  856. geterrormessage(err);
  857. }
  858. else {
  859. pword=parse_plib_script(0,"",err,pfirstword,true,NULL);
  860. if (err) {
  861. geterrormessage(err);
  862. }
  863. }
  864. killplib(pfirstword,pfirstgroup);
  865. if (err) return false;
  866. return true;
  867. }
  868. void plibhelp() {
  869. ishelp=true;
  870. helpheader((xtring)"global");
  871. plib_declarations(0,"");
  872. ishelp=false;
  873. }