PageRenderTime 62ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/EMBOSS-6.4.0/ajax/core/ajquery.c

#
C | 2861 lines | 1527 code | 678 blank | 656 comment | 204 complexity | e7dae42574d9828e35220b8f8d28432b MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.0, Apache-2.0
  1. /*
  2. ** This is free software; you can redistribute it and/or
  3. ** modify it under the terms of the GNU Library General Public License
  4. ** as published by the Free Software Foundation; either version 2
  5. ** of the License, or (at your option) any later version.
  6. **
  7. ** This program is distributed in the hope that it will be useful,
  8. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ** GNU General Public License for more details.
  11. **
  12. ** You should have received a copy of the GNU Library General Public License
  13. ** along with this program; if not, write to the Free Software
  14. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. ******************************************************************************/
  16. #include "ajax.h"
  17. static AjBool queryRegInitDone = AJFALSE;
  18. static AjPStr queryFormat = NULL;
  19. static AjPStr queryList = NULL;
  20. static AjPStr querySvr = NULL;
  21. static AjPStr queryDb = NULL;
  22. static AjPStr queryChr = NULL;
  23. static AjPStr queryTest = NULL;
  24. static AjPRegexp queryRegAsis = NULL;
  25. static AjPRegexp queryRegSvr = NULL;
  26. static AjPRegexp queryRegDbId = NULL;
  27. static AjPRegexp queryRegDbField = NULL;
  28. static AjPRegexp queryRegFmt = NULL;
  29. static AjPRegexp queryRegFieldId = NULL;
  30. static AjPRegexp queryRegId = NULL;
  31. static AjPRegexp queryRegList = NULL;
  32. static AjPRegexp queryRegRange = NULL;
  33. static AjPRegexp queryRegWild = NULL;
  34. static void queryWildComp(void);
  35. static void queryRegInit(void);
  36. static const AjPStr queryGetFieldC(const AjPQuery query,
  37. const char* txt);
  38. static const char* queryDatatypeName[] =
  39. {
  40. "unknown", "sequence", "features", "assembly",
  41. "obo", "resource", "taxon",
  42. "text", NULL
  43. };
  44. /* @filesection ajquery *******************************************************
  45. **
  46. ** @nam1rule aj Function belongs to the AJAX library.
  47. **
  48. ******************************************************************************/
  49. /* @datasection [AjPQuery] Query object ***************************************
  50. **
  51. ** Function is for manipulating query objects
  52. **
  53. ** @nam2rule Query
  54. **
  55. ******************************************************************************/
  56. /* @section Query Constructors ************************************************
  57. **
  58. ** All constructors return a new query object by pointer. It
  59. ** is the responsibility of the user to first destroy any previous
  60. ** query object. The target pointer does not need to be
  61. ** initialised to NULL, but it is good programming practice to do so
  62. ** anyway.
  63. **
  64. ** @fdata [AjPQuery]
  65. **
  66. ** @nam3rule New Constructor
  67. ** @argrule New datatype [const AjEDataType] Enumerated datatype
  68. **
  69. ** @valrule * [AjPQuery]
  70. **
  71. ** @fcategory new
  72. **
  73. ******************************************************************************/
  74. /* @func ajQueryNew ********************************************************
  75. **
  76. ** Creates a new query object for a specific datatype from the
  77. ** AJDATATYPE enumerated types
  78. **
  79. ** @param [r] datatype [const AjEDataType] Enumerated datatype
  80. ** @return [AjPQuery] New query object.
  81. ** @@
  82. ******************************************************************************/
  83. AjPQuery ajQueryNew(const AjEDataType datatype)
  84. {
  85. AjPQuery pthis;
  86. AJNEW0(pthis);
  87. pthis->SvrName = ajStrNew();
  88. pthis->DbName = ajStrNew();
  89. pthis->DbAlias= ajStrNew();
  90. pthis->QueryFields = ajListNew();
  91. pthis->ResultsList = ajListNew();
  92. pthis->ResultsTable = ajTablestrNewConst(100);
  93. pthis->DbIdentifier = ajStrNew();
  94. pthis->DbAccession = ajStrNew();
  95. pthis->Wild = ajFalse;
  96. pthis->Method = ajStrNew();
  97. pthis->Formatstr = ajStrNew();
  98. pthis->IndexDir = ajStrNew();
  99. pthis->Directory = ajStrNew();
  100. pthis->Filename = ajStrNew();
  101. pthis->Application = ajStrNew();
  102. pthis->Field = ajStrNew();
  103. pthis->DbFilter = ajStrNew();
  104. pthis->DbReturn = ajStrNew();
  105. pthis->QueryType = AJQUERY_UNKNOWN;
  106. pthis->Access = NULL;
  107. pthis->DataType = datatype;
  108. pthis->QryData = NULL;
  109. pthis->Fpos = NULLFPOS;
  110. pthis->QryDone = ajFalse;
  111. pthis->HasAcc = ajTrue;
  112. return pthis;
  113. }
  114. /* @section Query Destructors *************************************************
  115. **
  116. ** Destruction destroys all internal data structures and frees the
  117. ** memory allocated for the query object.
  118. **
  119. ** @fdata [AjPQuery]
  120. **
  121. ** @nam3rule Del destructor
  122. **
  123. ** @argrule Del pthis [AjPQuery*] Query
  124. **
  125. ** @valrule * [void]
  126. **
  127. ** @fcategory delete
  128. **
  129. ******************************************************************************/
  130. /* @func ajQueryDel ***********************************************************
  131. **
  132. ** Deletes a query object
  133. **
  134. ** @param [d] pthis [AjPQuery*] Address of query object
  135. ** @return [void]
  136. ** @@
  137. ******************************************************************************/
  138. void ajQueryDel(AjPQuery* pthis)
  139. {
  140. AjPQuery thys;
  141. AjPQueryField field = NULL;
  142. AjPTextAccess textaccess;
  143. if(!pthis)
  144. return;
  145. if(!*pthis)
  146. return;
  147. ajDebug("ajQueryDel db:'%S' svr: '%S' fields:%u\n",
  148. (*pthis)->DbName, (*pthis)->SvrName,
  149. ajListGetLength((*pthis)->QueryFields));
  150. thys = *pthis;
  151. ajStrDel(&thys->SvrName);
  152. ajStrDel(&thys->DbName);
  153. ajStrDel(&thys->DbAlias);
  154. ajStrDel(&thys->DbType);
  155. ajStrDel(&thys->DbIdentifier);
  156. ajStrDel(&thys->DbAccession);
  157. ajStrDel(&thys->DbFilter);
  158. ajStrDel(&thys->DbReturn);
  159. while(ajListPop(thys->QueryFields, (void **) &field))
  160. ajQueryfieldDel(&field);
  161. ajListFree(&thys->QueryFields);
  162. ajListFreeData(&thys->ResultsList);
  163. ajTableFree(&thys->ResultsTable);
  164. ajStrDel(&thys->Method);
  165. ajStrDel(&thys->Qlinks);
  166. ajStrDel(&thys->Formatstr);
  167. ajStrDel(&thys->IndexDir);
  168. ajStrDel(&thys->Directory);
  169. ajStrDel(&thys->Filename);
  170. ajStrDel(&thys->Exclude);
  171. ajStrDel(&thys->DbFields);
  172. ajStrDel(&thys->DbUrl);
  173. ajStrDel(&thys->DbProxy);
  174. ajStrDel(&thys->DbHttpVer);
  175. ajStrDel(&thys->ServerVer);
  176. ajStrDel(&thys->Field);
  177. ajStrDel(&thys->QryString);
  178. ajStrDel(&thys->Application);
  179. if(thys->QryData)
  180. {
  181. textaccess = thys->TextAccess;
  182. if(textaccess)
  183. {
  184. if(textaccess->AccessFree)
  185. textaccess->AccessFree(thys);
  186. }
  187. AJFREE(thys->QryData);
  188. }
  189. AJFREE(*pthis);
  190. return;
  191. }
  192. /* @section Query Casts ***************************************************
  193. **
  194. ** These functions examine the contents of a query object
  195. ** and return some derived information. Some of them provide access to
  196. ** the internal components of a query object. They are
  197. ** provided for programming convenience but should be used with
  198. ** caution.
  199. **
  200. ** @fdata [AjPQuery]
  201. **
  202. ** @nam3rule Get Return a value
  203. ** @nam4rule Datatype Return name of datatype
  204. ** @nam4rule Id Return id query term
  205. ** @nam4rule Format Return format name
  206. ** @nam4rule Query Return a report of the query string
  207. ** @nam3rule Getall Return all values
  208. ** @nam4rule Fields Return a set of standard query fields
  209. **
  210. ** @argrule * query [const AjPQuery] Query object
  211. ** @argrule GetQuery Pdest [AjPStr*] Returned query string
  212. **
  213. **
  214. ** @valrule * [AjBool] True on success
  215. ** @valrule *Fields [const AjPList] List of field objects found
  216. ** @valrule *Format [const AjPStr] Format name
  217. ** @valrule *Id [const AjPStr] Wildcard ID
  218. ** @valrule *Datatype [const char*] Datatype standard name
  219. **
  220. ** @fcategory cast
  221. **
  222. ******************************************************************************/
  223. /* @func ajQueryGetDatatype ***************************************************
  224. **
  225. ** Returns the query datatype from a query
  226. **
  227. ** @param [r] query [const AjPQuery] Query
  228. ** @return [const char*] Standard name for query datatype
  229. ******************************************************************************/
  230. const char* ajQueryGetDatatype(const AjPQuery query)
  231. {
  232. if(query->DataType > AJDATATYPE_MAX)
  233. return "invalid";
  234. return queryDatatypeName[query->DataType];
  235. }
  236. /* @func ajQueryGetFormat *****************************************************
  237. **
  238. ** Returns the format name from a query
  239. **
  240. ** @param [r] query [const AjPQuery] Query
  241. ** @return [const AjPStr] Format name
  242. ******************************************************************************/
  243. const AjPStr ajQueryGetFormat(const AjPQuery query)
  244. {
  245. return query->Formatstr;
  246. }
  247. /* @func ajQueryGetId *********************************************************
  248. **
  249. ** Returns the ID query string from a query
  250. **
  251. ** @param [r] query [const AjPQuery] Query
  252. ** @return [const AjPStr] Wildcard ID query string
  253. ******************************************************************************/
  254. const AjPStr ajQueryGetId(const AjPQuery query)
  255. {
  256. return queryGetFieldC(query, "id");
  257. }
  258. /* @func ajQueryGetQuery *******************************************************
  259. **
  260. ** Returns a report of the query string from a query
  261. **
  262. ** @param [r] query [const AjPQuery] Query
  263. ** @param [w] Pdest [AjPStr*] Query string
  264. ** @return [AjBool] True on success
  265. ******************************************************************************/
  266. AjBool ajQueryGetQuery(const AjPQuery query, AjPStr *Pdest)
  267. {
  268. AjIList iter = NULL;
  269. AjPQueryField field = NULL;
  270. const char* queryLinkNames[] = {"", "OR", "AND", "EOR", "NOT", "ELSE"};
  271. if(!Pdest)
  272. return ajFalse;
  273. ajStrAssignClear(Pdest);
  274. iter = ajListIterNewread(query->QueryFields);
  275. while(!ajListIterDone(iter))
  276. {
  277. field = ajListIterGet(iter);
  278. if(field->Link != AJQLINK_INIT)
  279. ajFmtPrintAppS(Pdest, " %s ", queryLinkNames[field->Link]);
  280. ajFmtPrintAppS(Pdest, "%S:%S", field->Field, field->Wildquery);
  281. }
  282. ajListIterDel(&iter);
  283. return ajTrue;
  284. }
  285. /* @func ajQueryGetallFields **************************************************
  286. **
  287. ** Returns the standard sequence query string from a query
  288. **
  289. ** @param [r] query [const AjPQuery] Query
  290. ** @return [const AjPList] List of field objects
  291. ******************************************************************************/
  292. const AjPList ajQueryGetallFields(const AjPQuery query)
  293. {
  294. return query->QueryFields;
  295. }
  296. /* @funcstatic queryGetFieldC *************************************************
  297. **
  298. ** Returns the query string from a query for a named field
  299. **
  300. ** @param [r] query [const AjPQuery] Query
  301. ** @param [r] txt [const char*] Field name
  302. ** @return [const AjPStr] Wildcard ID query string
  303. ******************************************************************************/
  304. static const AjPStr queryGetFieldC(const AjPQuery query,
  305. const char* txt)
  306. {
  307. AjPStr ret = NULL;
  308. AjIList iter = NULL;
  309. AjPQueryField field = NULL;
  310. iter = ajListIterNewread(query->QueryFields);
  311. while(!ajListIterDone(iter))
  312. {
  313. field = ajListIterGet(iter);
  314. if(ajStrMatchC(field->Field, txt))
  315. {
  316. ret = field->Wildquery;
  317. break;
  318. }
  319. }
  320. ajListIterDel(&iter);
  321. return ret;
  322. }
  323. /* @section Query Casts *******************************************************
  324. **
  325. ** These functions use the contents of a query object but do
  326. ** not make any changes.
  327. **
  328. ** @fdata [AjPQuery]
  329. **
  330. ** @nam3rule Is Test for a property
  331. ** @nam3rule Known Test a property matches known options
  332. ** @nam4rule Set Query has some query field(s) defined
  333. ** @nam4rule KnownField Test field name is defined for the data source
  334. ** @suffix C Character string input
  335. ** @suffix S String input
  336. **
  337. ** @argrule * thys [const AjPQuery] query
  338. ** @argrule C fieldtxt [const char*] Field name
  339. ** @argrule S field [const AjPStr] Field name
  340. **
  341. ** @valrule * [AjBool] True if property exists
  342. **
  343. ** @fcategory cast
  344. **
  345. ******************************************************************************/
  346. /* @func ajQueryIsSet *********************************************************
  347. **
  348. ** Tests whether any element of a query has been set.
  349. **
  350. ** @param [r] thys [const AjPQuery] Query object.
  351. ** @return [AjBool] ajTrue if query should be made. ajFalse if the query
  352. ** includes all entries.
  353. ** @@
  354. ******************************************************************************/
  355. AjBool ajQueryIsSet(const AjPQuery thys)
  356. {
  357. ajDebug("ajQueryIsSet list:%u\n", ajListGetLength(thys->QueryFields));
  358. if(ajListGetLength(thys->QueryFields))
  359. return ajTrue;
  360. return ajFalse;
  361. }
  362. /* @func ajQueryKnownFieldC ***************************************************
  363. **
  364. ** Checks whether a query field is defined for a database as a "fields:"
  365. ** string in the database definition.
  366. **
  367. ** @param [r] thys [const AjPQuery] Query object
  368. ** @param [r] fieldtxt [const char*] field name
  369. ** @return [AjBool] ajTrue if the field is defined
  370. ******************************************************************************/
  371. AjBool ajQueryKnownFieldC(const AjPQuery thys, const char* fieldtxt)
  372. {
  373. AjPStrTok handle = NULL;
  374. AjPStr token = NULL;
  375. ajDebug("ajQueryKnownFieldC qry '%s' fields '%S'\n",
  376. fieldtxt, thys->DbFields);
  377. ajStrTokenAssignC(&handle, thys->DbFields, "\t ,;\n\r");
  378. while(ajStrTokenNextParse(&handle, &token))
  379. {
  380. if(ajStrMatchCaseC(token, fieldtxt))
  381. {
  382. ajDebug("ajQueryKnownFieldC match '%S'\n", token);
  383. ajStrTokenDel(&handle);
  384. ajStrDel(&token);
  385. return ajTrue;
  386. }
  387. }
  388. ajStrTokenDel(&handle);
  389. ajStrDel(&token);
  390. if(ajCharMatchCaseC(fieldtxt, "id"))
  391. return ajTrue;
  392. if(thys->HasAcc && ajCharMatchCaseC(fieldtxt, "acc"))
  393. return ajTrue;
  394. return ajFalse;
  395. }
  396. /* @func ajQueryKnownFieldS ***************************************************
  397. **
  398. ** Checks whether a query field is defined for a database as a "fields:"
  399. ** string in the database definition.
  400. **
  401. ** @param [r] thys [const AjPQuery] Query object
  402. ** @param [r] field [const AjPStr] field name
  403. ** @return [AjBool] ajTrue if the field is defined
  404. ******************************************************************************/
  405. AjBool ajQueryKnownFieldS(const AjPQuery thys, const AjPStr field)
  406. {
  407. return ajQueryKnownFieldC(thys, ajStrGetPtr(field));
  408. }
  409. /* @section Modifiers *********************************************************
  410. **
  411. ** Modify values in a query object
  412. **
  413. ** @fdata [AjPQuery]
  414. **
  415. ** @nam3rule Add Add content
  416. ** @nam4rule AddField Add a query field
  417. ** @nam5rule And Add an AND query field
  418. ** @nam5rule Else Add an ELSE query field
  419. ** @nam5rule Eor Add an EOR query field
  420. ** @nam5rule Not Add a NOT query field
  421. ** @nam5rule Or Add an OR query field
  422. ** @nam3rule Set Set internals
  423. ** @nam4rule Wild Set wildcard property
  424. ** @nam3rule Clear Reset for reuse
  425. ** @nam3rule Starclear Reset all fields that are just '*' for 'match all'
  426. ** @suffix C Character string data
  427. ** @suffix S String data
  428. **
  429. ** @argrule * thys [AjPQuery] Query object
  430. ** @argrule C fieldtxt [const char*] Field name
  431. ** @argrule C wildquerytxt [const char*] Query string
  432. ** @argrule S field [const AjPStr] Field name
  433. ** @argrule S wildquery [const AjPStr] Query string
  434. **
  435. ** @valrule * [void]
  436. ** @valrule *AddField [AjBool] True on success
  437. ** @valrule *Wild [AjBool] True if query had wildcard(s)
  438. **
  439. ** @fcategory modify
  440. **
  441. ******************************************************************************/
  442. /* @func ajQueryAddFieldAndC **************************************************
  443. **
  444. ** Adds a query with an 'AND' operator
  445. **
  446. ** @param [u] thys [AjPQuery] Query object
  447. ** @param [r] fieldtxt [const char*] field name
  448. ** @param [r] wildquerytxt [const char*] wildcard query string
  449. ** @return [AjBool] ajTrue on success
  450. ******************************************************************************/
  451. AjBool ajQueryAddFieldAndC(AjPQuery thys, const char* fieldtxt,
  452. const char* wildquerytxt)
  453. {
  454. AjPQueryField qryfield;
  455. qryfield = ajQueryfieldNewC(fieldtxt, wildquerytxt, AJQLINK_AND);
  456. if(!thys->QueryFields)
  457. thys->QueryFields = ajListNew();
  458. ajListPushAppend(thys->QueryFields, qryfield);
  459. qryfield = NULL;
  460. return ajTrue;
  461. }
  462. /* @func ajQueryAddFieldAndS **************************************************
  463. **
  464. ** Adds a query with an 'AND' operator
  465. **
  466. ** @param [u] thys [AjPQuery] Query object
  467. ** @param [r] field [const AjPStr] field name
  468. ** @param [r] wildquery [const AjPStr] wildcard query string
  469. ** @return [AjBool] ajTrue on success
  470. ******************************************************************************/
  471. AjBool ajQueryAddFieldAndS(AjPQuery thys, const AjPStr field,
  472. const AjPStr wildquery)
  473. {
  474. AjPQueryField qryfield;
  475. qryfield = ajQueryfieldNewS(field, wildquery, AJQLINK_AND);
  476. if(!thys->QueryFields)
  477. thys->QueryFields = ajListNew();
  478. ajListPushAppend(thys->QueryFields, qryfield);
  479. qryfield = NULL;
  480. return ajTrue;
  481. }
  482. /* @func ajQueryAddFieldElseC *************************************************
  483. **
  484. ** Adds a query with an 'ELSE' operator
  485. **
  486. ** @param [u] thys [AjPQuery] Query object
  487. ** @param [r] fieldtxt [const char*] field name
  488. ** @param [r] wildquerytxt [const char*] wildcard query string
  489. ** @return [AjBool] ajTrue on success
  490. ******************************************************************************/
  491. AjBool ajQueryAddFieldElseC(AjPQuery thys, const char* fieldtxt,
  492. const char* wildquerytxt)
  493. {
  494. AjPQueryField qryfield;
  495. qryfield = ajQueryfieldNewC(fieldtxt, wildquerytxt, AJQLINK_ELSE);
  496. if(!thys->QueryFields)
  497. thys->QueryFields = ajListNew();
  498. ajListPushAppend(thys->QueryFields, qryfield);
  499. qryfield = NULL;
  500. return ajTrue;
  501. }
  502. /* @func ajQueryAddFieldElseS *************************************************
  503. **
  504. ** Adds a query with an 'ELSE' operator
  505. **
  506. ** @param [u] thys [AjPQuery] Query object
  507. ** @param [r] field [const AjPStr] field name
  508. ** @param [r] wildquery [const AjPStr] wildcard query string
  509. ** @return [AjBool] ajTrue on success
  510. ******************************************************************************/
  511. AjBool ajQueryAddFieldElseS(AjPQuery thys, const AjPStr field,
  512. const AjPStr wildquery)
  513. {
  514. AjPQueryField qryfield;
  515. qryfield = ajQueryfieldNewS(field, wildquery, AJQLINK_ELSE);
  516. if(!thys->QueryFields)
  517. thys->QueryFields = ajListNew();
  518. ajListPushAppend(thys->QueryFields, qryfield);
  519. qryfield = NULL;
  520. return ajTrue;
  521. }
  522. /* @func ajQueryAddFieldEorC **************************************************
  523. **
  524. ** Adds a query with an 'EOR' operator
  525. **
  526. ** @param [u] thys [AjPQuery] Query object
  527. ** @param [r] fieldtxt [const char*] field name
  528. ** @param [r] wildquerytxt [const char*] wildcard query string
  529. ** @return [AjBool] ajTrue on success
  530. ******************************************************************************/
  531. AjBool ajQueryAddFieldEorC(AjPQuery thys, const char* fieldtxt,
  532. const char* wildquerytxt)
  533. {
  534. AjPQueryField qryfield;
  535. qryfield = ajQueryfieldNewC(fieldtxt, wildquerytxt, AJQLINK_EOR);
  536. if(!thys->QueryFields)
  537. thys->QueryFields = ajListNew();
  538. ajListPushAppend(thys->QueryFields, qryfield);
  539. qryfield = NULL;
  540. return ajTrue;
  541. }
  542. /* @func ajQueryAddFieldEorS **************************************************
  543. **
  544. ** Adds a query with an 'EOR' operator
  545. **
  546. ** @param [u] thys [AjPQuery] Query object
  547. ** @param [r] field [const AjPStr] field name
  548. ** @param [r] wildquery [const AjPStr] wildcard query string
  549. ** @return [AjBool] ajTrue on success
  550. ******************************************************************************/
  551. AjBool ajQueryAddFieldEorS(AjPQuery thys, const AjPStr field,
  552. const AjPStr wildquery)
  553. {
  554. AjPQueryField qryfield;
  555. qryfield = ajQueryfieldNewS(field, wildquery, AJQLINK_EOR);
  556. if(!thys->QueryFields)
  557. thys->QueryFields = ajListNew();
  558. ajListPushAppend(thys->QueryFields, qryfield);
  559. qryfield = NULL;
  560. return ajTrue;
  561. }
  562. /* @func ajQueryAddFieldNotC **************************************************
  563. **
  564. ** Adds a query with a 'NOT' operator
  565. **
  566. ** @param [u] thys [AjPQuery] Query object
  567. ** @param [r] fieldtxt [const char*] field name
  568. ** @param [r] wildquerytxt [const char*] wildcard query string
  569. ** @return [AjBool] ajTrue on success
  570. ******************************************************************************/
  571. AjBool ajQueryAddFieldNotC(AjPQuery thys, const char* fieldtxt,
  572. const char* wildquerytxt)
  573. {
  574. AjPQueryField qryfield;
  575. qryfield = ajQueryfieldNewC(fieldtxt, wildquerytxt, AJQLINK_NOT);
  576. if(!thys->QueryFields)
  577. thys->QueryFields = ajListNew();
  578. ajListPushAppend(thys->QueryFields, qryfield);
  579. qryfield = NULL;
  580. return ajTrue;
  581. }
  582. /* @func ajQueryAddFieldNotS **************************************************
  583. **
  584. ** Adds a query with a 'NOT' operator
  585. **
  586. ** @param [u] thys [AjPQuery] Query object
  587. ** @param [r] field [const AjPStr] field name
  588. ** @param [r] wildquery [const AjPStr] wildcard query string
  589. ** @return [AjBool] ajTrue on success
  590. ******************************************************************************/
  591. AjBool ajQueryAddFieldNotS(AjPQuery thys, const AjPStr field,
  592. const AjPStr wildquery)
  593. {
  594. AjPQueryField qryfield;
  595. qryfield = ajQueryfieldNewS(field, wildquery, AJQLINK_NOT);
  596. if(!thys->QueryFields)
  597. thys->QueryFields = ajListNew();
  598. ajListPushAppend(thys->QueryFields, qryfield);
  599. qryfield = NULL;
  600. return ajTrue;
  601. }
  602. /* @func ajQueryAddFieldOrC ***************************************************
  603. **
  604. ** Adds a query with an 'OR' operator
  605. **
  606. ** @param [u] thys [AjPQuery] Query object
  607. ** @param [r] fieldtxt [const char*] field name
  608. ** @param [r] wildquerytxt [const char*] wildcard query string
  609. ** @return [AjBool] ajTrue on success
  610. ******************************************************************************/
  611. AjBool ajQueryAddFieldOrC(AjPQuery thys, const char* fieldtxt,
  612. const char* wildquerytxt)
  613. {
  614. AjPQueryField qryfield;
  615. if(!thys->QueryFields)
  616. thys->QueryFields = ajListNew();
  617. if(!ajListGetLength(thys->QueryFields))
  618. qryfield = ajQueryfieldNewC(fieldtxt, wildquerytxt, AJQLINK_INIT);
  619. else
  620. qryfield = ajQueryfieldNewC(fieldtxt, wildquerytxt, AJQLINK_OR);
  621. ajListPushAppend(thys->QueryFields, qryfield);
  622. qryfield = NULL;
  623. return ajTrue;
  624. }
  625. /* @func ajQueryAddFieldOrS ***************************************************
  626. **
  627. ** Adds a query with an 'OR' operator
  628. **
  629. ** @param [u] thys [AjPQuery] Query object
  630. ** @param [r] field [const AjPStr] field name
  631. ** @param [r] wildquery [const AjPStr] wildcard query string
  632. ** @return [AjBool] ajTrue on success
  633. ******************************************************************************/
  634. AjBool ajQueryAddFieldOrS(AjPQuery thys, const AjPStr field,
  635. const AjPStr wildquery)
  636. {
  637. AjPQueryField qryfield;
  638. if(!thys->QueryFields)
  639. thys->QueryFields = ajListNew();
  640. if(!ajListGetLength(thys->QueryFields))
  641. qryfield = ajQueryfieldNewS(field, wildquery, AJQLINK_INIT);
  642. else
  643. qryfield = ajQueryfieldNewS(field, wildquery, AJQLINK_OR);
  644. ajListPushAppend(thys->QueryFields, qryfield);
  645. qryfield = NULL;
  646. return ajTrue;
  647. }
  648. /* @func ajQueryClear *********************************************************
  649. **
  650. ** Resets a query object to a clean state for reuse.
  651. ** Keep the begin, end and reverse values.
  652. **
  653. ** @param [u] thys [AjPQuery] query object
  654. ** @return [void]
  655. ** @@
  656. ******************************************************************************/
  657. void ajQueryClear(AjPQuery thys)
  658. {
  659. AjPQueryField field = NULL;
  660. void *result;
  661. ajStrSetClear(&thys->SvrName);
  662. ajStrSetClear(&thys->DbName);
  663. ajStrSetClear(&thys->DbAlias);
  664. ajStrSetClear(&thys->DbType);
  665. while(ajListPop(thys->QueryFields, (void **) &field))
  666. ajQueryfieldDel(&field);
  667. while(ajListPop(thys->ResultsList, (void **) &result))
  668. continue;
  669. ajTableClear(thys->ResultsTable);
  670. ajStrSetClear(&thys->Method);
  671. ajStrSetClear(&thys->Qlinks);
  672. ajStrSetClear(&thys->Formatstr);
  673. ajStrSetClear(&thys->IndexDir);
  674. ajStrSetClear(&thys->Directory);
  675. ajStrSetClear(&thys->Filename);
  676. ajStrSetClear(&thys->Exclude);
  677. ajStrSetClear(&thys->DbFields);
  678. ajStrSetClear(&thys->DbUrl);
  679. ajStrSetClear(&thys->DbProxy);
  680. ajStrSetClear(&thys->DbHttpVer);
  681. ajStrSetClear(&thys->ServerVer);
  682. ajStrSetClear(&thys->Field);
  683. ajStrSetClear(&thys->QryString);
  684. ajStrSetClear(&thys->Application);
  685. ajStrSetClear(&thys->DbIdentifier);
  686. ajStrSetClear(&thys->DbAccession);
  687. ajStrSetClear(&thys->DbFilter);
  688. ajStrSetClear(&thys->DbReturn);
  689. thys->Fpos = 0L;
  690. thys->TextAccess = NULL;
  691. thys->Access = NULL;
  692. if(thys->QryData)
  693. AJFREE(thys->QryData);
  694. thys->QueryType = AJQUERY_UNKNOWN;
  695. /*thys->DataType = AJDATATYPE_UNKNOWN;*/
  696. thys->QryDone = ajFalse;
  697. thys->SetServer = ajFalse;
  698. thys->SetDatabase = ajFalse;
  699. thys->SetQuery = ajFalse;
  700. thys->Wild = ajFalse;
  701. thys->CaseId = ajFalse;
  702. thys->HasAcc = ajTrue; /* default true in ajQueryNew */
  703. return;
  704. }
  705. /* @func ajQuerySetWild ******************************************************
  706. **
  707. ** Tests whether a query includes wild cards in any element,
  708. ** or can return more than one entry (keyword and some other search terms
  709. ** will find multiple entries)
  710. **
  711. ** @param [u] thys [AjPQuery] Query object.
  712. ** @return [AjBool] ajTrue if query had wild cards.
  713. ** @@
  714. ******************************************************************************/
  715. AjBool ajQuerySetWild(AjPQuery thys)
  716. {
  717. AjIList iter = NULL;
  718. AjPQueryField field = NULL;
  719. AjBool ret = ajFalse;
  720. ajuint ifield = 0;
  721. if(!queryRegWild)
  722. queryWildComp();
  723. ajDebug("ajQuerySetWild fields: %u\n",
  724. ajListGetLength(thys->QueryFields));
  725. /* first test for ID query */
  726. iter = ajListIterNewread(thys->QueryFields);
  727. while(!ajListIterDone(iter))
  728. {
  729. field = ajListIterGet(iter);
  730. ajDebug("test1 query %S '%S' %u\n",
  731. field->Field, field->Wildquery, field->Link);
  732. if(ajStrMatchC(field->Field, "id"))
  733. {
  734. if(ajRegExec(queryRegWild, field->Wildquery))
  735. {
  736. thys->Wild = ajTrue;
  737. ajDebug("wild id query %S '%S'\n",
  738. field->Field, field->Wildquery);
  739. ajListIterDel(&iter);
  740. return ajTrue;
  741. }
  742. break;
  743. }
  744. }
  745. ajListIterRewind(iter);
  746. /* now test the other fields */
  747. while(!ajListIterDone(iter))
  748. {
  749. field = ajListIterGet(iter);
  750. ajDebug("test2 query %S '%S'\n",
  751. field->Field, field->Wildquery);
  752. if(ifield++ && field->Link != AJQLINK_ELSE) /* field [|&!^] field */
  753. {
  754. ajListIterDel(&iter);
  755. return ajTrue;
  756. }
  757. if(ajStrMatchC(field->Field, "id"))
  758. continue;
  759. if(ajRegExec(queryRegWild, field->Wildquery))
  760. {
  761. thys->Wild = ajTrue;
  762. ajDebug("wild query %S '%S'\n",
  763. field->Field, field->Wildquery);
  764. ajListIterDel(&iter);
  765. return ajTrue;
  766. }
  767. if(!ajStrMatchC(field->Field, "acc"))
  768. ret = ajTrue;
  769. }
  770. ajListIterDel(&iter);
  771. ajDebug("wildcard in stored query: %B\n", ret);
  772. return ret;
  773. }
  774. /* @func ajQueryStarclear *****************************************************
  775. **
  776. ** Clears elements of a query object if they are simply "*" because this
  777. ** is equivalent to a null string.
  778. **
  779. ** @param [u] thys [AjPQuery] Query object.
  780. ** @return [void]
  781. ** @@
  782. ******************************************************************************/
  783. void ajQueryStarclear(AjPQuery thys)
  784. {
  785. AjIList iter = NULL;
  786. AjPQueryField field = NULL;
  787. iter = ajListIterNew(thys->QueryFields);
  788. while(!ajListIterDone(iter))
  789. {
  790. field = ajListIterGet(iter);
  791. if(ajStrMatchC(field->Wildquery, "*"))
  792. {
  793. ajDebug("ajQueryStarclear keep field %S '%S'\n",
  794. field->Field, field->Wildquery);
  795. /*
  796. ajQueryfieldDel(&field);
  797. ajListIterRemove(iter);
  798. */
  799. }
  800. }
  801. ajListIterDel(&iter);
  802. return;
  803. }
  804. /* @section Debug *************************************************************
  805. **
  806. ** Reports sequence contents for debugging purposes
  807. **
  808. ** @fdata [AjPQuery]
  809. ** @fcategory misc
  810. **
  811. ** @nam3rule Trace Print report to debug file (if any)
  812. ** @nam4rule TraceTitle Print report to debug file (if any) with title
  813. **
  814. ** @argrule * thys [const AjPQuery] query object.
  815. **
  816. ** @valrule * [void]
  817. **
  818. ******************************************************************************/
  819. /* @func ajQueryTrace *********************************************************
  820. **
  821. ** Debug calls to trace the data in a query object.
  822. **
  823. ** @param [r] thys [const AjPQuery] query object.
  824. ** @return [void]
  825. ** @@
  826. ******************************************************************************/
  827. void ajQueryTrace(const AjPQuery thys)
  828. {
  829. AjIList iter = NULL;
  830. AjPQueryField field = NULL;
  831. const char* operators[] =
  832. {
  833. "init",
  834. "OR", "AND", "EOR", "NOT",
  835. "ELSE"
  836. };
  837. ajDebug( " Query Trace\n");
  838. if(ajStrGetLen(thys->SvrName))
  839. ajDebug( " SvrName: '%S'\n", thys->SvrName);
  840. if(ajStrGetLen(thys->DbName))
  841. ajDebug( " DbName: '%S'\n", thys->DbName);
  842. if(ajStrGetLen(thys->DbAlias))
  843. ajDebug( " DbAlias: '%S'\n", thys->DbAlias);
  844. if(ajStrGetLen(thys->DbType))
  845. ajDebug( " DbType: '%S' (%d)\n", thys->DbType, thys->QueryType);
  846. iter = ajListIterNewread(thys->QueryFields);
  847. while(!ajListIterDone(iter))
  848. {
  849. field = ajListIterGet(iter);
  850. if(field->Link < AJQLINK_MAX)
  851. ajDebug( " %S: '%S' %d (%s)\n",
  852. field->Field, field->Wildquery,
  853. field->Link, operators[field->Link]);
  854. else
  855. ajDebug( " %S: '%S' %d\n",
  856. field->Field, field->Wildquery,
  857. field->Link);
  858. }
  859. ajListIterDel(&iter);
  860. ajDebug( " Case-sensitive Id: '%B'\n", thys->CaseId);
  861. ajDebug( " Has accession: %B\n", thys->HasAcc);
  862. if(ajStrGetLen(thys->Method))
  863. ajDebug( " Method: '%S'\n", thys->Method);
  864. if(ajStrGetLen(thys->Formatstr))
  865. ajDebug( " Formatstr: '%S'\n", thys->Formatstr);
  866. if(ajStrGetLen(thys->IndexDir))
  867. ajDebug( " IndexDir: '%S'\n", thys->IndexDir);
  868. if(ajStrGetLen(thys->Directory))
  869. ajDebug( " Directory: '%S'\n", thys->Directory);
  870. if(ajStrGetLen(thys->Filename))
  871. ajDebug( " Filename: '%S'\n", thys->Filename);
  872. if(ajStrGetLen(thys->Exclude))
  873. ajDebug( " Exclude: '%S'\n", thys->Exclude);
  874. if(ajStrGetLen(thys->DbFields))
  875. ajDebug( " DbFields: '%S'\n", thys->DbFields);
  876. if(ajStrGetLen(thys->DbIdentifier))
  877. ajDebug( " DbIdentifier: '%S'\n", thys->DbIdentifier);
  878. if(ajStrGetLen(thys->DbAccession))
  879. ajDebug( " DbAccession: '%S'\n", thys->DbAccession);
  880. if(ajStrGetLen(thys->DbFilter))
  881. ajDebug( " DbFilter: '%S'\n", thys->DbFilter);
  882. if(ajStrGetLen(thys->DbReturn))
  883. ajDebug( " DbReturn: '%S'\n", thys->DbReturn);
  884. if(ajStrGetLen(thys->DbUrl))
  885. ajDebug( " DbUrl: '%S'\n", thys->DbUrl);
  886. if(ajStrGetLen(thys->DbProxy))
  887. ajDebug( " DbProxy: '%S'\n", thys->DbProxy);
  888. if(ajStrGetLen(thys->DbHttpVer))
  889. ajDebug( " DbHttpVer: '%S'\n", thys->DbHttpVer);
  890. if(ajStrGetLen(thys->Field))
  891. ajDebug( " Field: '%S'\n", thys->Field);
  892. if(ajStrGetLen(thys->QryString))
  893. ajDebug( " QryString: '%S'\n", thys->QryString);
  894. if(ajStrGetLen(thys->Application))
  895. ajDebug( " Application: '%S'\n", thys->Application);
  896. ajDebug( " Fpos: %ld\n", thys->Fpos);
  897. ajDebug( " QryDone: %B\n", thys->QryDone);
  898. ajDebug( " Wildcard in query: %B\n", thys->Wild);
  899. if(thys->Access)
  900. ajDebug( " Access: exists\n");
  901. if(thys->QryData)
  902. ajDebug( " QryData: exists\n");
  903. return;
  904. }
  905. /* @section exit **************************************************************
  906. **
  907. ** Functions called on exit from the program by ajExit to do
  908. ** any necessary cleanup and to report internal statistics to the debug file
  909. **
  910. ** @fdata [AjPQuery]
  911. ** @fnote general exit functions, no arguments
  912. **
  913. ** @nam3rule Exit Cleanup and report on exit
  914. **
  915. ** @valrule * [void]
  916. **
  917. ** @fcategory misc
  918. ******************************************************************************/
  919. /* @func ajQueryExit **********************************************************
  920. **
  921. ** Cleans up query processing internal memory
  922. **
  923. ** @return [void]
  924. ** @@
  925. ******************************************************************************/
  926. void ajQueryExit(void)
  927. {
  928. ajStrDel(&queryFormat);
  929. ajStrDel(&queryList);
  930. ajStrDel(&querySvr);
  931. ajStrDel(&queryDb);
  932. ajStrDel(&queryChr);
  933. ajStrDel(&queryTest);
  934. ajRegFree(&queryRegAsis);
  935. ajRegFree(&queryRegSvr);
  936. ajRegFree(&queryRegDbId);
  937. ajRegFree(&queryRegDbField);
  938. ajRegFree(&queryRegFmt);
  939. ajRegFree(&queryRegFieldId);
  940. ajRegFree(&queryRegId);
  941. ajRegFree(&queryRegList);
  942. ajRegFree(&queryRegRange);
  943. ajRegFree(&queryRegWild);
  944. return;
  945. }
  946. /* @datasection [AjPQueryField] Query fields **********************************
  947. **
  948. ** Query field processing
  949. **
  950. ** @nam2rule Queryfield
  951. **
  952. ******************************************************************************/
  953. /* @section constructors ******************************************************
  954. **
  955. ** Constructors
  956. **
  957. ** @fdata [AjPQueryField]
  958. **
  959. ** @nam3rule New Constructor
  960. ** @suffix C Character string data
  961. ** @suffix S String data
  962. **
  963. ** @argrule C fieldtxt [const char*] Field name
  964. ** @argrule C wildtxt [const char*] Wildcard query string
  965. ** @argrule S field [const AjPStr] Field name
  966. ** @argrule S wild [const AjPStr] Wildcard query string
  967. ** @argrule New oper [AjEQryLink] Operator
  968. **
  969. ** @valrule * [AjPQueryField] Query field object
  970. **
  971. ** @fcategory new
  972. **
  973. ******************************************************************************/
  974. /* @func ajQueryfieldNewC *****************************************************
  975. **
  976. ** Constructor for a query field
  977. **
  978. ** @param [r] fieldtxt [const char*] Field name
  979. ** @param [r] wildtxt [const char*] Wildcard query string
  980. ** @param [r] oper [AjEQryLink] Operator
  981. **
  982. ** @return [AjPQueryField] Query field
  983. ******************************************************************************/
  984. AjPQueryField ajQueryfieldNewC(const char* fieldtxt,
  985. const char* wildtxt,
  986. AjEQryLink oper)
  987. {
  988. AjPQueryField ret;
  989. AJNEW0(ret);
  990. ajDebug("ajQueryfieldNewC '%s' '%s'\n", fieldtxt, wildtxt);
  991. ret->Field = ajStrNewC(fieldtxt);
  992. ret->Wildquery = ajStrNewC(wildtxt);
  993. ret->Link = oper;
  994. ajStrFmtLower(&ret->Field);
  995. return ret;
  996. }
  997. /* @func ajQueryfieldNewS *****************************************************
  998. **
  999. ** Constructor for a query field
  1000. **
  1001. ** @param [r] field [const AjPStr] Field name
  1002. ** @param [r] wild [const AjPStr] Wildcard query string
  1003. ** @param [r] oper [AjEQryLink] Operator
  1004. **
  1005. ** @return [AjPQueryField] Query field
  1006. ******************************************************************************/
  1007. AjPQueryField ajQueryfieldNewS(const AjPStr field,
  1008. const AjPStr wild,
  1009. AjEQryLink oper)
  1010. {
  1011. AjPQueryField ret;
  1012. AJNEW0(ret);
  1013. ajDebug("ajQueryfieldNewS '%S' '%S'\n", field, wild);
  1014. ret->Field = ajStrNewS(field);
  1015. ret->Wildquery = ajStrNewS(wild);
  1016. ret->Link = oper;
  1017. ajStrFmtLower(&ret->Field);
  1018. return ret;
  1019. }
  1020. /* @section Query Field Destructors *******************************************
  1021. **
  1022. ** Destruction destroys all internal data structures and frees the
  1023. ** memory allocated for the query field object.
  1024. **
  1025. ** @fdata [AjPQueryField]
  1026. **
  1027. ** @nam3rule Del destructor
  1028. **
  1029. ** @argrule Del Pthis [AjPQueryField*] Query field
  1030. **
  1031. ** @valrule * [void]
  1032. **
  1033. ** @fcategory delete
  1034. **
  1035. ******************************************************************************/
  1036. /* @func ajQueryfieldDel ******************************************************
  1037. **
  1038. ** Destructor for a query field
  1039. **
  1040. ** @param [d] Pthis [AjPQueryField*] Query field object to be deleted
  1041. **
  1042. ** @return [void]
  1043. ******************************************************************************/
  1044. void ajQueryfieldDel(AjPQueryField *Pthis)
  1045. {
  1046. AjPQueryField thys;
  1047. if(!Pthis) return;
  1048. if(!*Pthis) return;
  1049. thys = *Pthis;
  1050. ajStrDel(&thys->Field);
  1051. ajStrDel(&thys->Wildquery);
  1052. AJFREE(*Pthis);
  1053. return;
  1054. }
  1055. /* @datasection [AjPList] Query field list ************************************
  1056. **
  1057. ** Query fields lists are handled internally. Only static functions
  1058. ** should appear here
  1059. **
  1060. ** @nam2rule Querylist Query list processing
  1061. **
  1062. ******************************************************************************/
  1063. /* @section Debug *************************************************************
  1064. **
  1065. ** Reports sequence contents for debugging purposes
  1066. **
  1067. ** @fdata [AjPList]
  1068. ** @fcategory misc
  1069. **
  1070. ** @nam3rule Trace Print report to debug file (if any)
  1071. ** @nam4rule TraceTitle Print report to debug file (if any) with title
  1072. **
  1073. ** @argrule * list [const AjPList] query list
  1074. **
  1075. ** @valrule * [void]
  1076. **
  1077. ******************************************************************************/
  1078. /* @func ajQuerylistTrace *****************************************************
  1079. **
  1080. ** Traces the nodes in a query list
  1081. **
  1082. ** @param [r] list [const AjPList] The query list
  1083. ** @return [void]
  1084. ******************************************************************************/
  1085. void ajQuerylistTrace(const AjPList list)
  1086. {
  1087. AjIList iter;
  1088. AjPQueryList node;
  1089. ajuint i = 0;
  1090. iter = ajListIterNewread(list);
  1091. ajDebug("ajQuerylistTrace %d nodes\n", ajListGetLength(list));
  1092. while(!ajListIterDone(iter))
  1093. {
  1094. node = (AjPQueryList) ajListIterGet(iter);
  1095. ajDebug("%3d: '%S' '%S' %d\n",
  1096. ++i, node->Qry,
  1097. node->Formatstr, node->Format);
  1098. }
  1099. ajListIterDel(&iter);
  1100. ajDebug("...Done...\n");
  1101. return;
  1102. }
  1103. /* @funcstatic queryWildComp **************************************************
  1104. **
  1105. ** Compiles the regular expressions for testing wild cards in queries.
  1106. ** These are held in static storage and built once only if needed.
  1107. **
  1108. ** @return [void]
  1109. ** @@
  1110. ******************************************************************************/
  1111. static void queryWildComp(void)
  1112. {
  1113. if(!queryRegWild)
  1114. queryRegWild = ajRegCompC("[*?]");
  1115. return;
  1116. }
  1117. /* @datasection [AjPStr] Query string *****************************************
  1118. **
  1119. ** Function is for manipulating query strings
  1120. **
  1121. ** @nam2rule Querystr
  1122. **
  1123. ******************************************************************************/
  1124. /* @section Query string parsing **********************************************
  1125. **
  1126. ** Parses a query string and removes the processed string trokens
  1127. **
  1128. ** @fdata [AjPStr]
  1129. ** @fcategory modify
  1130. **
  1131. ** @nam3rule Parse Parse the string
  1132. ** @nam4rule ParseFormat Parse the format prefix
  1133. ** @nam4rule ParseListfile Parse the listfile prefix
  1134. ** @nam4rule ParseRange Parse the range suffix
  1135. ** @nam4rule ParseRead Parse a text query and read data
  1136. **
  1137. ** @argrule Parse Pqry [AjPStr*] Query string
  1138. ** @argrule Format textin [AjPTextin] Text input object
  1139. ** @argrule Format findformat [AjBool function] Function to validate
  1140. ** format name
  1141. ** @argrule Range Pbegin [ajint*] Begin position
  1142. ** @argrule Range Pend [ajint*] End position
  1143. ** @argrule Range Prev [AjBool*] Reverse orientation
  1144. ** @argrule Read textin [AjPTextin] Text input object
  1145. ** @argrule Read findformat [AjBool function] Function to validate format name
  1146. ** @argrule Read Pnontext [AjBool*] True if access is a non-text method
  1147. ** to be processed by the caller
  1148. **
  1149. ** @valrule * [AjBool] True if found
  1150. ** @valrule *Format [const AjPStr] Format name if found
  1151. **
  1152. ******************************************************************************/
  1153. /* @func ajQuerystrParseFormat ************************************************
  1154. **
  1155. ** Parses a query (USA, UFO or general query).
  1156. **
  1157. ** Then tests for "format::" and returns this if it is found,
  1158. ** removing the format part of the original query.
  1159. **
  1160. ** @param [u] Pqry [AjPStr*] Query string
  1161. ** @param [u] textin [AjPTextin] Text input object
  1162. ** @param [f] findformat [AjBool function] Function to validate format name
  1163. ** @return [const AjPStr] Format name if found
  1164. ** @@
  1165. ******************************************************************************/
  1166. const AjPStr ajQuerystrParseFormat(AjPStr *Pqry, AjPTextin textin,
  1167. AjBool findformat(const AjPStr format,
  1168. ajint *iformat))
  1169. {
  1170. AjBool fmtstat = ajFalse; /* status returns from regex tests */
  1171. AjBool asisstat = ajFalse;
  1172. AjBool liststat = ajFalse;
  1173. AjPQuery qry = textin->Query;
  1174. ajDebug("++ajQuerystrParseFormat '%S'\n", *Pqry);
  1175. if(!queryRegInitDone)
  1176. queryRegInit();
  1177. /* Strip any leading spaces */
  1178. ajStrTrimC(Pqry," \t\n");
  1179. asisstat = ajRegExec(queryRegAsis, *Pqry);
  1180. liststat = ajRegExec(queryRegList, *Pqry);
  1181. if(liststat || asisstat)
  1182. return NULL;
  1183. fmtstat = ajRegExec(queryRegFmt, *Pqry);
  1184. if(!fmtstat)
  1185. {
  1186. if(ajStrGetLen(textin->Formatstr))
  1187. {
  1188. if(findformat(textin->Formatstr, &textin->Format))
  1189. ajStrAssignS(&qry->Formatstr, textin->Formatstr);
  1190. }
  1191. return NULL;
  1192. }
  1193. ajRegSubI(queryRegFmt, 1, &queryFormat);
  1194. ajRegSubI(queryRegFmt, 2, Pqry);
  1195. ajDebug("found format %S rest '%S'\n", queryFormat, *Pqry);
  1196. ajStrAssignEmptyC(&queryFormat, "unknown");
  1197. if(findformat(queryFormat, &textin->Format))
  1198. {
  1199. ajStrAssignS(&qry->Formatstr, queryFormat);
  1200. ajStrAssignS(&textin->Formatstr, queryFormat);
  1201. }
  1202. else
  1203. ajErr("Unknown input format '%S'\n", queryFormat);
  1204. return queryFormat;
  1205. }
  1206. /* @func ajQuerystrParseListfile **********************************************
  1207. **
  1208. ** Parses a query (USA, UFO or general query).
  1209. **
  1210. ** Then tests for "list::" or "@" and returns true if found,
  1211. ** removing the filename only in the origiunal query.
  1212. **
  1213. ** @param [u] Pqry [AjPStr*] Query string
  1214. ** @return [AjBool] True if found
  1215. ** @@
  1216. ******************************************************************************/
  1217. AjBool ajQuerystrParseListfile(AjPStr *Pqry)
  1218. {
  1219. AjBool liststat = ajFalse; /* status returns from regex tests */
  1220. ajDebug("++ajQuerystrParseListfile '%S'\n", *Pqry);
  1221. if(!queryRegInitDone)
  1222. queryRegInit();
  1223. /* Strip any leading spaces */
  1224. ajStrTrimC(Pqry," \t\n");
  1225. ajStrAssignS(&queryTest, *Pqry);
  1226. liststat = ajRegExec(queryRegList, queryTest);
  1227. if(liststat)
  1228. {
  1229. ajRegSubI(queryRegList, 2, Pqry);
  1230. ajDebug("list found @%S\n", *Pqry);
  1231. }
  1232. return liststat;
  1233. }
  1234. /* @func ajQuerystrParseRange *************************************************
  1235. **
  1236. ** Parses a query (USA, UFO or general query).
  1237. **
  1238. ** Tests for "[n:n:r]" range and sets this if it is found,
  1239. ** removing the range part of the original query.
  1240. **
  1241. ** @param [u] Pqry [AjPStr*] Query string
  1242. ** @param [u] Pbegin [ajint*] Begin position
  1243. ** @param [u] Pend [ajint*] End position
  1244. ** @param [u] Prev [AjBool*] Reverse orientation
  1245. ** @return [AjBool] True if range was found.
  1246. ** @@
  1247. ******************************************************************************/
  1248. AjBool ajQuerystrParseRange(AjPStr *Pqry, ajint *Pbegin, ajint *Pend,
  1249. AjBool *Prev)
  1250. {
  1251. AjPStr tmpstr = NULL;
  1252. AjBool rangestat = ajFalse;
  1253. if(!queryRegInitDone)
  1254. queryRegInit();
  1255. ajDebug("ajQuerystrParseRange: '%S'\n", *Pqry);
  1256. rangestat = ajRegExec(queryRegRange, *Pqry);
  1257. if(rangestat)
  1258. {
  1259. ajRegSubI(queryRegRange, 2, &tmpstr);
  1260. if(ajStrGetLen(tmpstr))
  1261. ajStrToInt(tmpstr, Pbegin);
  1262. ajRegSubI(queryRegRange, 3, &tmpstr);
  1263. if(ajStrGetLen(tmpstr))
  1264. ajStrToInt(tmpstr, Pend);
  1265. ajRegSubI(queryRegRange, 5, &tmpstr);
  1266. if(ajStrGetLen(tmpstr))
  1267. *Prev = ajTrue;
  1268. ajStrDel(&tmpstr);
  1269. ajRegSubI(queryRegRange, 1, Pqry);
  1270. ajDebug("range found [%d:%d:%b]\n",
  1271. *Pbegin, *Pend, *Prev);
  1272. }
  1273. return rangestat;
  1274. }
  1275. /* @func ajQuerystrParseRead **************************************************
  1276. **
  1277. ** Parses a query (USA, UFO or general query).
  1278. **
  1279. ** First tests for "asis" input and sets the rest of the query as input data.
  1280. **
  1281. ** Then tests for server:dbname:query or dbname:query
  1282. ** and tests whether the access method is a text method.
  1283. **
  1284. ** For text access, calls the access method to opens the file
  1285. ** (and set the file position).
  1286. **
  1287. ** If there is no database, looks for file:query and opens the file.
  1288. ** If an offset is provided as %offset sets the file position
  1289. **
  1290. ** If the file does now exist, tests again for a database of that name
  1291. ** from any known server.
  1292. **
  1293. ** If no text data was found, returns the filled in datatype-specific details
  1294. **
  1295. ** @param [u] Pqry [AjPStr*] Query string
  1296. ** @param [u] textin [AjPTextin] Text input structure.
  1297. ** @param [f] findformat [AjBool function] Function to validate format name
  1298. ** @param [w] Pnontext [AjBool*] True if access is a non-text method
  1299. ** @return [AjBool] ajTrue on success.
  1300. ** @@
  1301. ******************************************************************************/
  1302. AjBool ajQuerystrParseRead(AjPStr *Pqry, AjPTextin textin,
  1303. AjBool findformat(const AjPStr format,
  1304. ajint *iformat),
  1305. AjBool *Pnontext)
  1306. {
  1307. AjPQuery qry;
  1308. AjBool svrstat = ajFalse;
  1309. AjBool regstat = ajFalse;
  1310. AjBool dbstat = ajFalse;
  1311. AjBool accstat = ajFalse; /* return status from reading something */
  1312. AjBool asisstat = ajFalse;
  1313. AjBool drcatstat = ajFalse;
  1314. AjBool inbraces = ajFalse;
  1315. AjPStr braceopen = NULL;
  1316. AjPStr braceclose = NULL;
  1317. AjPStr idstr = NULL;
  1318. AjPStr lastoper= NULL;
  1319. AjPStr operstr = NULL;
  1320. AjPStr allfields = NULL;
  1321. AjPStr qrystring = NULL;
  1322. AjPStr qrystr = NULL;
  1323. ajlong i;
  1324. AjPStrTok handle = NULL;
  1325. AjPResource drcat = NULL;
  1326. AjPTextAccess textaccess = NULL;
  1327. ajint iformat = 0;
  1328. #ifdef __CYGWIN__
  1329. char cygd;
  1330. #endif
  1331. *Pnontext = ajFalse;
  1332. qry = textin->Query;
  1333. if(qry->QryDone)
  1334. return ajFalse;
  1335. ajStrAssignS(&qry->QryString, *Pqry);
  1336. ajStrDel(&qry->Field); /* clear it. we test this for regstat */
  1337. if(!queryRegInitDone)
  1338. queryRegInit();
  1339. ajDebug("++ajQrystrParseRead '%S' '%S' %d\n",
  1340. *Pqry,
  1341. textin->Formatstr, textin->Format);
  1342. /* Strip any leading spaces */
  1343. ajStrTrimC(Pqry," \t\n");
  1344. asisstat = ajRegExec(queryRegAsis, *Pqry);
  1345. if(asisstat)
  1346. {
  1347. ajStrAssignC(&queryFormat, "asis");
  1348. if(!findformat(queryFormat, &textin->Format))
  1349. {
  1350. ajErr("asis:: not supported by datatype for '%S'",
  1351. *Pqry);
  1352. return ajFalse;
  1353. }
  1354. ajStrAssignS(&qry->Formatstr, queryFormat);
  1355. ajStrAssignS(&textin->Formatstr, queryFormat);
  1356. ajRegSubI(queryRegAsis, 1, &qry->Filename);
  1357. ajDebug("asis sequence '%S'\n", qry->Filename);
  1358. return ajTextinAccessAsis(textin);
  1359. }
  1360. #ifdef __CYGWIN__
  1361. if(ajStrGetCharPos(*Pqry,1) == ':')
  1362. {
  1363. cygd = ajStrGetCharFirst(*Pqry);
  1364. if(isupper((int) cygd))
  1365. ajStrPasteCountK(Pqry, 0, (char) tolower((int)cygd), 1);
  1366. ajStrPasteCountK(Pqry, 1, '/', 1);
  1367. ajStrInsertC(Pqry, 0, "/cygdrive/");
  1368. }
  1369. #endif
  1370. ajDebug("query to test: '%S'\n\n", *Pqry);
  1371. svrstat = ajRegExec(queryRegSvr, *Pqry);
  1372. ajDebug("server dbexp: %B '%S'\n", svrstat, *Pqry);
  1373. if(svrstat)
  1374. {
  1375. ajRegSubI(queryRegSvr, 1, &querySvr);
  1376. /* clear it if this was really a file */
  1377. if(ajNamServer(querySvr))
  1378. {
  1379. ajRegPost(queryRegSvr, Pqry);
  1380. ajDebug("found server %S, rest '%S'\n",
  1381. querySvr, *Pqry);
  1382. }
  1383. else
  1384. {
  1385. ajDebug("unknown server %S, try dbname\n", querySvr);
  1386. ajStrDel(&querySvr);
  1387. svrstat = ajFalse;
  1388. }
  1389. }
  1390. regstat = ajFalse;
  1391. if(ajRegExec(queryRegDbField, *Pqry))
  1392. {
  1393. regstat = ajTrue;
  1394. ajDebug("dbname queryRegDbField: %B '%S'\n", regstat, *Pqry);
  1395. /* test dbname-field: or dbname: */
  1396. ajRegSubI(queryRegDbField, 1, &queryDb);
  1397. ajRegSubI(queryRegDbField, 4, &allfields);
  1398. ajRegSubI(queryRegDbField, 5, &braceclose);
  1399. ajStrTrimWhite(&allfields);
  1400. if(!ajStrMatchC(braceclose, "}"))
  1401. ajErr("Bad query syntax: unclosed braces '%S'", *Pqry);
  1402. inbraces = ajTrue; /* braces in the regex */
  1403. qry->QueryType = AJQUERY_QUERY;
  1404. ajDebug("Query db: '%S' allfields: '%S'\n", queryDb, allfields);
  1405. /* clear it if this was really a file */
  1406. if(ajStrGetLen(querySvr))
  1407. {
  1408. if(!ajNamAliasServer(&queryDb, querySvr))
  1409. {
  1410. ajDebug("unknown dbname %S for server %S\n",
  1411. queryDb, querySvr);
  1412. ajStrDel(&queryDb);
  1413. ajStrDel(&qry->Field);
  1414. regstat = ajFalse;
  1415. }
  1416. }
  1417. else if(!ajNamAliasDatabase(&queryDb))
  1418. {
  1419. drcat = ajResourceNewDrcat(queryDb);
  1420. if(drcat)
  1421. {
  1422. ajDebug("database '%S' found via DRCAT datatype %u\n",
  1423. queryDb, qry->DataType);
  1424. if(!ajResourceGetDbdata(drcat, qry, findformat))
  1425. regstat = ajFalse;
  1426. else
  1427. drcatstat = ajTrue;
  1428. ajResourceDel(&drcat);
  1429. }
  1430. else
  1431. {
  1432. ajDebug("unknown dbname %S, try filename\n", queryDb);
  1433. regstat = ajFalse;
  1434. }
  1435. if(!regstat)
  1436. {
  1437. ajStrDel(&queryDb);
  1438. ajStrDel(&qry->Field);
  1439. }
  1440. }
  1441. ajStrDel(&braceclose);
  1442. }
  1443. else if(ajRegExec(queryRegDbId, *Pqry))
  1444. {
  1445. regstat = ajTrue;
  1446. ajDebug("dbname queryRegDbId: %B '%S'\n", regstat, *Pqry);
  1447. /* test dbname-field: or dbname: */
  1448. ajRegSubI(queryRegDbId, 1, &queryDb);
  1449. ajRegSubI(queryRegDbId, 3, &qry->Field);
  1450. ajDebug("Query db: '%S' field: '%S'\n", queryDb, qry->Field);
  1451. /* clear it if this was really a file */
  1452. if(ajStrGetLen(querySvr))
  1453. {
  1454. if(!ajNamAliasServer(&queryDb, querySvr))
  1455. {
  1456. ajDebug("unknown dbname %S for server %S\n",
  1457. queryDb, querySvr);
  1458. ajStrDel(&queryDb);
  1459. ajStrDel(&qry->Field);
  1460. regstat = ajFalse;
  1461. }
  1462. }
  1463. else if(!ajNamAliasDatabase(&queryDb))
  1464. {
  1465. drcat = ajResourceNewDrcat(queryDb);
  1466. if(drcat)
  1467. {
  1468. ajDebug("database '%S' found via DRCAT datatype %u\n",
  1469. queryDb, qry->DataType);
  1470. if(!ajResourceGetDbdata(drcat, qry, findformat))
  1471. regstat = ajFalse;
  1472. else
  1473. {
  1474. if(qry->DataType == AJDATATYPE_URL)
  1475. {
  1476. qry->QryData = drcat;
  1477. drcat = NULL;
  1478. }
  1479. drcatstat = ajTrue;
  1480. }
  1481. ajResourceDel(&drcat);
  1482. }
  1483. else
  1484. {
  1485. ajDebug("unknown dbname %S, try filename\n", queryDb);
  1486. regstat = ajFalse;
  1487. }
  1488. if(!regstat)
  1489. {
  1490. ajStrDel(&queryDb);
  1491. ajStrDel(&qry->Field);
  1492. }
  1493. }
  1494. /* test :identifier or :queryterm */
  1495. if(regstat)
  1496. {
  1497. ajRegSubI(queryRegDbId, 6, &braceopen);
  1498. ajRegSubI(queryRegDbId, 8, &braceclose);
  1499. ajRegSubI(queryRegDbId, 7, &qrystring);
  1500. ajStrTrimWhite(&qrystring);
  1501. if(*MAJSTRGETPTR(braceopen))
  1502. {
  1503. if(*MAJSTRGETPTR(braceclose))
  1504. inbraces = ajTrue;
  1505. else
  1506. {
  1507. ajErr("Bad query syntax: unclosed braces '%S'", *Pqry);
  1508. ajStrDel(&qrystring);
  1509. return ajFalse;
  1510. }
  1511. }
  1512. else
  1513. {
  1514. if(*MAJSTRGETPTR(braceclose))
  1515. {
  1516. ajErr("Bad query syntax: unopened braces '%S'", *Pqry);
  1517. ajStrDel(&qrystring);
  1518. return ajFalse;
  1519. }
  1520. }
  1521. ajDebug("Query qrystring: '%S' open: '%S' close: '%S' "
  1522. "inbraces: %B\n",
  1523. qrystring, braceopen, braceclose, inbraces);
  1524. ajStrDel(&braceopen);
  1525. ajStrDel(&braceclose);
  1526. }
  1527. }
  1528. if(regstat)
  1529. {
  1530. ajStrAssignS(&qry->DbName, queryDb);
  1531. if(ajStrGetLen(querySvr))
  1532. {
  1533. ajStrAssignS(&qry->SvrName, querySvr);
  1534. ajDebug("found server '%S' dbname '%S' level: '%S' "
  1535. "qrystring: '%S'\n",
  1536. qry->SvrName, qry->DbName, qry->Field, qrystring);
  1537. dbstat = ajNamSvrData(qry, 0);
  1538. if(!dbstat)
  1539. {
  1540. ajStrDel(&qrystring);
  1541. return ajFalse;
  1542. }
  1543. }
  1544. else
  1545. {
  1546. ajDebug("found dbname '%S' level: '%S' qrystring: '%S'\n",
  1547. qry->DbName, qry->Field, qrystring);
  1548. if(drcatstat)
  1549. dbstat = ajTrue;
  1550. else
  1551. {
  1552. dbstat = ajNamDbData(qry, 0);
  1553. if(!dbstat)
  1554. {
  1555. ajStrDel(&qrystring);
  1556. return ajFalse;
  1557. }
  1558. }
  1559. }
  1560. /* dbname-field or dbname-{field:qry} */
  1561. if(dbstat && ajStrGetLen(allfields))
  1562. {
  1563. ajDebug(" db qrystring '%S' allfields '%S' inbraces: %B\n",
  1564. qrystring, allfields, inbraces);
  1565. if(inbraces)
  1566. {
  1567. qry->QueryType = AJQUERY_QUERY;
  1568. ajNamDbQuery(qry);
  1569. if(ajStrGetCharFirst(allfields) == '!')
  1570. ajStrInsertK(&allfields, 0, '*');
  1571. ajStrAssignC(&lastoper, "|");
  1572. ajStrTokenAssignC(&handle, allfields, "|&^!");
  1573. while(ajStrTokenNextParseDelimiters(&handle, &qrystr,
  1574. &operstr))
  1575. {
  1576. if(ajStrGetLen(operstr))
  1577. {
  1578. if(!ajStrGetLen(qry->Qlinks) ||
  1579. (ajStrFindAnyS(qry->Qlinks, operstr) == -1))
  1580. {
  1581. ajErr("Query link operator '%S' not supported "
  1582. "by access method '%S' for database '%S'"
  1583. " allowed links are '%S'",
  1584. operstr, qry->Method, qry->DbName,
  1585. qry->Qlinks);
  1586. return ajFalse;
  1587. }
  1588. }
  1589. ajStrTrimWhite(&qrystr);
  1590. i = ajStrFindAnyK(qrystr, ':');
  1591. if(i>0)
  1592. {
  1593. ajStrAssignSubS(&qry->Field, qrystr, 0, i-1);
  1594. ajStrAssignSubS(&idstr, qrystr, i+1, -1);
  1595. ajDebug("qrystr: '%S' field: '%S' qry: '%S'\n",
  1596. qrystr, qry->Field, idstr);
  1597. }
  1598. if(!ajQueryKnownFieldS(qry, qry->Field))
  1599. {
  1600. ajErr("Query '%S' query field '%S' not defined"
  1601. " for database '%S'",
  1602. *Pqry, qry->Field, qry->DbName);
  1603. ajStrDel(&qrystring);
  1604. return ajFalse;
  1605. }
  1606. switch(ajStrGetCharFirst(lastoper))
  1607. {
  1608. case '|':
  1609. ajQueryAddFieldOrS(qry, qry->Field, idstr);
  1610. ajDebug("ajQueryAddFieldOrS.a '%S' '%S'\n",
  1611. qry->Field, idstr);
  1612. break;
  1613. case '&':
  1614. ajQueryAddFieldAndS(qry, qry->Field, idstr);
  1615. ajDebug("ajQueryAddFieldAndS.a '%S' '%S'\n",
  1616. qry->Field, idstr);
  1617. break;
  1618. case '!':
  1619. ajQueryAddFieldNotS(qry, qry->Field, idstr);
  1620. ajDebug("ajQueryAddFieldNotS.a '%S' '%S'\n",
  1621. qry->Field, idstr);
  1622. break;
  1623. case '^':
  1624. ajQueryAddFieldEorS(qry, qry->Field, idstr);
  1625. ajDebug("ajQueryAddFieldEorS.a '%S' '%S'\n",
  1626. qry->Field, idstr);
  1627. break;
  1628. default:
  1629. ajErr("bad query syntax: "
  1630. "unknown operator '%S'",
  1631. lastoper);
  1632. break;
  1633. }
  1634. ajStrAssignS(&lastoper, operstr);
  1635. ajStrTrimWhite(&lastoper);
  1636. }
  1637. ajStrDel(&qrystr);
  1638. }
  1639. else
  1640. {
  1641. ajQueryAddFieldOrS(qry, qry->Field, qrystring);
  1642. ajDebug("ajQueryAddFieldOrS.b '%S' '%S'\n",
  1643. qry->Field, qrystring);
  1644. }
  1645. }
  1646. /* dbname-field:qry or dbname-field:{qrylist} */
  1647. else if(dbstat && ajStrGetLen(qrystring))
  1648. {
  1649. /* ajDebug(" qrystring %S\n", qrystring); */
  1650. if(ajStrGetLen(qry->Field))
  1651. {
  1652. ajDebug(" db Qrystring '%S' Field '%S'\n",
  1653. qrystring, qry->Field);
  1654. if(inbraces)
  1655. {
  1656. qry->QueryType = AJQUERY_QUERY;
  1657. ajNamDbQuery(qry);
  1658. if(ajStrGetCharFirst(qrystring) == '!')
  1659. ajStrInsertK(&qrystring, 0, '*');
  1660. ajStrAssignC(&lastoper, "|");
  1661. ajStrTokenAssignC(&handle, qrystring, "|&^!");
  1662. while(ajStrTokenNextParseDelimiters(&handle, &idstr,
  1663. &operstr))
  1664. {
  1665. if(ajStrGetLen(operstr) > 1)
  1666. {
  1667. ajErr("Query link multiple operators '%S'",
  1668. operstr);
  1669. return ajFalse;
  1670. }
  1671. ajStrTrimWhite(&idstr);
  1672. if(ajStrGetLen(operstr))
  1673. {
  1674. if(ajStrGetCharFirst(operstr) == ',')
  1675. ajStrAssignK(&operstr, '|');
  1676. if(!ajStrGetLen(qry->Qlinks) ||
  1677. (ajStrFindAnyS(qry->Qlinks, operstr) == -1))
  1678. {
  1679. ajErr("Query link operator '%S' not supported "
  1680. "by access method '%S' for database '%S'"
  1681. " allowed links are '%S'",
  1682. operstr, qry->Method, qry->DbName,
  1683. qry->Qlinks);
  1684. return ajFalse;
  1685. }
  1686. }
  1687. if(!ajQueryKnownFieldS(qry, qry->Field))
  1688. {
  1689. ajErr("Query '%S' query field '%S' not defined"
  1690. " for database '%S'",
  1691. *Pqry, qry->Field, qry->DbName);
  1692. ajStrDel(&qrystring);
  1693. return ajFalse;
  1694. }
  1695. switch(ajStrGetCharFirst(lastoper))
  1696. {
  1697. case '|':
  1698. ajQueryAddFieldOrS(qry, qry->Field, idstr);
  1699. ajDebug("ajQueryAddFieldOrS.c '%S' '%S'\n",
  1700. qry->Field, idstr);
  1701. break;
  1702. case '&':
  1703. ajQueryAddFieldAndS(qry, qry->Field, idstr);
  1704. ajDebug("ajQueryAddFieldAndS.c '%S' '%S'\n",
  1705. qry->Field, idstr);
  1706. break;
  1707. case '!':
  1708. ajQueryAddFieldNotS(qry, qry->Field, idstr);
  1709. ajDebug("ajQueryAddFieldNotS.c '%S' '%S'\n",
  1710. qry->Field, idstr);
  1711. break;
  1712. case '^':
  1713. ajQueryAddFieldEorS(qry, qry->Field, idstr);
  1714. ajDebug("ajQueryAddFieldEorS.c '%S' '%S'\n",
  1715. qry->Field, idstr);
  1716. break;
  1717. default:
  1718. ajErr("bad query syntax: "
  1719. "unknown operator '%S'",
  1720. lastoper);
  1721. break;
  1722. }
  1723. ajStrAssignS(&lastoper, operstr);
  1724. }
  1725. }
  1726. else
  1727. {
  1728. if(!ajQueryKnownFieldS(qry, qry->Field))
  1729. {
  1730. ajErr("Query '%S' query field '%S' not defined"
  1731. " for database '%S'",
  1732. *Pqry, qry->Field, qry->DbName);
  1733. ajStrDel(&qrystring);
  1734. return ajFalse;
  1735. }
  1736. ajQueryAddFieldOrS(qry, qry->Field, qrystring);
  1737. ajDebug("ajQueryAddFieldOrS.d '%S' '%S'\n",
  1738. qry->Field, qrystring);
  1739. }
  1740. }
  1741. /* no field specified dbname:id or dbname:{idlist} */
  1742. else
  1743. {
  1744. if(inbraces)
  1745. {
  1746. qry->QueryType = AJQUERY_QUERY;
  1747. ajNamDbQuery(qry);
  1748. if(ajStrGetCharFirst(qrystring) == '!')
  1749. ajStrInsertK(&qrystring, 0, '*');
  1750. ajStrAssignC(&lastoper, "|");
  1751. ajStrTokenAssignC(&handle, qrystring, "|&^!,");
  1752. ajDebug("testing '%S'\n", qrystring);
  1753. while(ajStrTokenNextParseDelimiters(&handle, &idstr,
  1754. &operstr))
  1755. {
  1756. if(ajStrGetLen(operstr) > 1)
  1757. {
  1758. ajErr("Query link multiple operators '%S'",
  1759. operstr);
  1760. return ajFalse;
  1761. }
  1762. if(ajStrGetLen(operstr))
  1763. {
  1764. if(ajStrGetCharFirst(operstr) == ',')
  1765. ajStrAssignK(&operstr, '|');
  1766. if(!ajStrGetLen(qry->Qlinks) ||
  1767. (ajStrFindAnyS(qry->Qlinks, operstr) == -1))
  1768. {
  1769. ajErr("Query link operator '%S' not supported "
  1770. "by access method '%S' for database '%S'"
  1771. " allowed links are '%S'",
  1772. operstr, qry->Method, qry->DbName,
  1773. qry->Qlinks);
  1774. return ajFalse;
  1775. }
  1776. }
  1777. ajStrTrimWhite(&idstr);
  1778. if(!ajStrGetLen(idstr))
  1779. {
  1780. if(ajStrGetLen(operstr))
  1781. ajErr("Bad query term '%S' before '%S' "
  1782. "in query '%S'",
  1783. idstr, operstr, qrystring);
  1784. else if(ajStrGetLen(lastoper))
  1785. ajErr("Bad query term '%S' after '%S' "
  1786. "in query '%S'",
  1787. idstr, lastoper, qrystring);
  1788. else
  1789. ajErr("Bad query term '%S' "
  1790. "in query '%S'",
  1791. idstr, qrystring);
  1792. }
  1793. ajDebug("lastoper: '%S' idstr: '%S' operstr: '%S'\n",
  1794. lastoper, idstr, operstr);
  1795. switch(ajStrGetCharFirst(lastoper))
  1796. {
  1797. case '|':
  1798. ajQueryAddFieldOrC(qry, "id",
  1799. MAJSTRGETPTR(idstr));
  1800. ajDebug("ajQueryAddFieldOrC.e '%s' '%S'\n",
  1801. "id", idstr);
  1802. break;
  1803. case '&':
  1804. ajQueryAddFieldAndC(qry, "id",
  1805. MAJSTRGETPTR(idstr));
  1806. ajDebug("ajQueryAddFieldAndC.a '%s' '%S'\n",
  1807. "id", idstr);
  1808. break;
  1809. case '!':
  1810. ajQueryAddFieldNotC(qry, "id",
  1811. MAJSTRGETPTR(idstr));
  1812. ajDebug("ajQueryAddFieldNotC.e '%s' '%S'\n",
  1813. "id", idstr);
  1814. break;
  1815. case '^':
  1816. ajQueryAddFieldEorC(qry, "id",
  1817. MAJSTRGETPTR(idstr));
  1818. ajDebug("ajQueryAddFieldEorC.e '%s' '%S'\n",
  1819. "id", idstr);
  1820. break;
  1821. default:
  1822. ajErr("bad query syntax: "
  1823. "unknown operator '%S'",
  1824. lastoper);
  1825. break;
  1826. }
  1827. if(qry->HasAcc && ajQueryKnownFieldC(qry, "acc"))
  1828. {
  1829. ajQueryAddFieldElseC(qry, "acc",
  1830. MAJSTRGETPTR(idstr));
  1831. ajDebug("ajQueryAddFieldElseC.e '%s' '%S'\n",
  1832. "acc", idstr);
  1833. }
  1834. if(ajQueryKnownFieldC(qry, "sv"))
  1835. {
  1836. ajQueryAddFieldElseC(qry, "sv",
  1837. MAJSTRGETPTR(idstr));
  1838. ajDebug("ajQueryAddFieldElseC.e '%s' '%S'\n",
  1839. "sv", idstr);
  1840. }
  1841. ajStrAssignS(&lastoper, operstr);
  1842. ajStrTrimWhite(&lastoper);
  1843. }
  1844. }
  1845. else
  1846. {
  1847. ajQueryAddFieldOrC(qry, "id",
  1848. MAJSTRGETPTR(qrystring));
  1849. ajDebug("ajQueryAddFieldOrC.f '%s' '%S'\n",
  1850. "id", qrystring);
  1851. if(qry->HasAcc && ajQueryKnownFieldC(qry, "acc"))
  1852. {
  1853. ajQueryAddFieldElseC(qry, "acc",
  1854. MAJSTRGETPTR(qrystring));
  1855. ajDebug("ajQueryAddFieldElseC.f '%s' '%S'\n",
  1856. "acc", qrystring);
  1857. }
  1858. if(ajQueryKnownFieldC(qry, "sv"))
  1859. {
  1860. ajQueryAddFieldElseC(qry, "sv",
  1861. MAJSTRGETPTR(qrystring));
  1862. ajDebug("ajQueryAddFieldElseC.f '%s' '%S'\n",
  1863. "sv", qrystring);
  1864. }
  1865. }
  1866. }
  1867. }
  1868. ajStrDel(&idstr);
  1869. ajStrDel(&lastoper);
  1870. ajStrDel(&operstr);
  1871. ajStrTokenDel(&handle);
  1872. ajStrDel(&allfields);
  1873. ajStrDel(&qrystring);
  1874. ajQueryStarclear(qry);
  1875. if(ajStrGetLen(querySvr))
  1876. dbstat = ajNamSvrQuery(qry);
  1877. else if(drcatstat)
  1878. dbstat = ajTrue;
  1879. else
  1880. dbstat = ajNamDbQuery(qry);
  1881. if(!dbstat)
  1882. {
  1883. ajErr("no access method available for '%S'", *Pqry);
  1884. return ajFalse;
  1885. }
  1886. if(findformat(qry->Formatstr, &iformat))
  1887. ajStrAssignS(&textin->Formatstr, qry->Formatstr);
  1888. else
  1889. {
  1890. ajErr("unknown format '%S' for '%S' type '%S'\n",
  1891. qry->Formatstr, *Pqry, qry->DbType);
  1892. return ajFalse;
  1893. }
  1894. if(iformat >= 0)
  1895. {
  1896. textin->Format = iformat;
  1897. textin->TextFormat = 0;
  1898. }
  1899. else
  1900. {
  1901. textin->TextFormat = - iformat;
  1902. textin->Format = 0;
  1903. }
  1904. ajDebug("database type: '%S' format '%S' %u textformat %u \n",
  1905. qry->DbType, qry->Formatstr,
  1906. textin->Format, textin->TextFormat);
  1907. ajQueryTrace(qry);
  1908. ajDebug("try TEXT access by method '%S'\n", qry->Method);
  1909. qry->TextAccess = ajCallTableGetS(textDbMethods,qry->Method);
  1910. if(!qry->TextAccess)
  1911. {
  1912. /* set up values for caller to try datatype-specific access */
  1913. *Pnontext = ajTrue;
  1914. return ajTrue;
  1915. }
  1916. /* ajDebug("trying access method '%S'\n", qry->Method); */
  1917. textaccess = qry->TextAccess;
  1918. accstat = textaccess->Access(textin);
  1919. if(accstat)
  1920. return ajTrue;
  1921. ajDebug("Database '%S' : access method '%S' failed\n",
  1922. qry->DbName, qry->Method);
  1923. return ajFalse;
  1924. }
  1925. ajDebug("no dbname specified\n");
  1926. ajDebug("\n");
  1927. /* no database name, try filename */
  1928. if(svrstat)
  1929. {
  1930. ajErr("Server '%S:' but no database name in '%S'", querySvr, *Pqry);
  1931. return ajFalse;
  1932. }
  1933. regstat = ajRegExec(queryRegFieldId, *Pqry);
  1934. ajDebug("entry-id regexp: %B\n", regstat);
  1935. ajDebug("filetest regexp queryRegFieldId: %B '%S'\n", regstat, *Pqry);
  1936. if(regstat)
  1937. {
  1938. ajRegSubI(queryRegFieldId, 1, &qry->Filename);
  1939. ajRegSubI(queryRegFieldId, 3, &qry->Field);
  1940. ajRegSubI(queryRegFieldId, 4, &queryChr);
  1941. ajRegSubI(queryRegFieldId, 5, &braceopen);
  1942. ajRegSubI(queryRegFieldId, 6, &qrystring);
  1943. ajRegSubI(queryRegFieldId, 7, &braceclose);
  1944. }
  1945. if(!regstat)
  1946. {
  1947. regstat = ajRegExec(queryRegId, *Pqry);
  1948. ajDebug("entry-id regexp: %B\n", regstat);
  1949. ajDebug("filetest regexp queryRegId: %B '%S'\n", regstat, *Pqry);
  1950. if(regstat)
  1951. {
  1952. ajRegSubI(queryRegId, 1, &qry->Filename);
  1953. ajRegSubI(queryRegId, 3, &queryChr);
  1954. ajRegSubI(queryRegId, 5, &braceopen);
  1955. ajRegSubI(queryRegId, 6, &qrystring);
  1956. ajRegSubI(queryRegId, 7, &braceclose);
  1957. }
  1958. }
  1959. if(regstat)
  1960. {
  1961. ajDebug("Query file: '%S' chr: '%S' field: '%S' qrystring: '%S' "
  1962. "open: '%S' close: '%S' inbraces: %B\n",
  1963. qry->Filename, queryChr, qry->Field, qrystring,
  1964. braceopen, braceclose, inbraces);
  1965. if(*MAJSTRGETPTR(braceopen))
  1966. {
  1967. if(*MAJSTRGETPTR(braceclose))
  1968. inbraces = ajTrue;
  1969. else
  1970. {
  1971. ajErr("Bad query syntax: unclosed braces '%S'", *Pqry);
  1972. return ajFalse;
  1973. }
  1974. }
  1975. else
  1976. {
  1977. if(*MAJSTRGETPTR(braceclose))
  1978. {
  1979. ajErr("Bad query syntax: unopened braces '%S'", *Pqry);
  1980. return ajFalse;
  1981. }
  1982. }
  1983. ajDebug("found filename %S\n", qry->Filename);
  1984. ajStrDel(&braceopen);
  1985. ajStrDel(&braceclose);
  1986. if(ajStrMatchC(queryChr, "%"))
  1987. {
  1988. ajStrToLong(qrystring, &qry->Fpos);
  1989. accstat = ajTextinAccessOffset(textin);
  1990. ajQueryTrace(qry);
  1991. if(accstat)
  1992. {
  1993. ajStrDel(&qrystring);
  1994. return ajTrue;
  1995. }
  1996. }
  1997. else
  1998. {
  1999. if(ajStrGetLen(qrystring))
  2000. {
  2001. ajDebug("file Qry '%S' Field '%S' hasAcc:%B queryChr '%S'\n",
  2002. qrystring, qry->Field, qry->HasAcc, queryChr);
  2003. if(ajStrGetLen(qry->Field)) /* set by dbname above */
  2004. {
  2005. /* ajDebug(" qry->Field %S\n", qry->Field); */
  2006. ajStrAssignC(&lastoper, "|");
  2007. ajStrTokenAssignC(&handle, qrystring, "|&!^ \t\n\r");
  2008. while(ajStrTokenNextParseDelimiters(&handle, &idstr,
  2009. &operstr))
  2010. {
  2011. switch(ajStrGetCharFirst(lastoper))
  2012. {
  2013. case '|':
  2014. ajQueryAddFieldOrS(qry, qry->Field, idstr);
  2015. ajDebug("ajQueryAddFieldOrS.g '%S' '%S'\n",
  2016. qry->Field, idstr);
  2017. break;
  2018. case '&':
  2019. ajQueryAddFieldAndS(qry, qry->Field, idstr);
  2020. ajDebug("ajQueryAddFieldAndS.g '%S' '%S'\n",
  2021. qry->Field, idstr);
  2022. break;
  2023. case '!':
  2024. ajQueryAddFieldNotS(qry, qry->Field, idstr);
  2025. ajDebug("ajQueryAddFieldNotS.g '%S' '%S'\n",
  2026. qry->Field, idstr);
  2027. break;
  2028. case '^':
  2029. ajQueryAddFieldEorS(qry, qry->Field, idstr);
  2030. ajDebug("ajQueryAddFieldEorS.g '%S' '%S'\n",
  2031. qry->Field, idstr);
  2032. break;
  2033. default:
  2034. ajErr("bad query syntax: "
  2035. "unknown operator '%S'",
  2036. lastoper);
  2037. break;
  2038. }
  2039. ajStrAssignS(&lastoper, operstr);
  2040. ajStrTrimWhite(&lastoper);
  2041. }
  2042. }
  2043. else /* no specific field */
  2044. {
  2045. if(inbraces)
  2046. {
  2047. qry->QueryType = AJQUERY_QUERY;
  2048. ajNamFileQuery(qry);
  2049. ajStrTokenAssignC(&handle, qrystring, " \t\n\r,;");
  2050. while(ajStrTokenNextParse(&handle, &idstr))
  2051. {
  2052. ajQueryAddFieldOrC(qry, "id",
  2053. MAJSTRGETPTR(idstr));
  2054. ajDebug("ajQueryAddFieldOrC.h '%s' '%S'\n",
  2055. "id", idstr);
  2056. if(qry->HasAcc && ajQueryKnownFieldC(qry, "acc"))
  2057. {
  2058. ajQueryAddFieldElseC(qry, "acc",
  2059. MAJSTRGETPTR(idstr));
  2060. ajDebug("ajQueryAddFieldElseC.h '%s' '%S'\n",
  2061. "acc", idstr);
  2062. }
  2063. if(ajQueryKnownFieldC(qry, "sv"))
  2064. {
  2065. ajQueryAddFieldElseC(qry, "sv",
  2066. MAJSTRGETPTR(idstr));
  2067. ajDebug("ajQueryAddFieldElseC.h '%s' '%S'\n",
  2068. "sv", idstr);
  2069. }
  2070. }
  2071. }
  2072. else
  2073. {
  2074. ajQueryAddFieldOrC(qry, "id",
  2075. MAJSTRGETPTR(qrystring));
  2076. ajDebug("ajQueryAddFieldOrC.i '%s' '%S'\n",
  2077. "id", qrystring);
  2078. if(qry->HasAcc && ajQueryKnownFieldC(qry, "acc"))
  2079. {
  2080. ajQueryAddFieldElseC(qry, "acc",
  2081. MAJSTRGETPTR(qrystring));
  2082. ajDebug("ajQueryAddFieldElseC.i '%s' '%S'\n",
  2083. "acc", qrystring);
  2084. }
  2085. if(ajQueryKnownFieldC(qry, "sv"))
  2086. {
  2087. ajQueryAddFieldElseC(qry, "sv",
  2088. MAJSTRGETPTR(qrystring));
  2089. ajDebug("ajQueryAddFieldElseC.i '%s' '%S'\n",
  2090. "sv", qrystring);
  2091. }
  2092. }
  2093. ajStrAssignS(&lastoper, operstr);
  2094. ajStrTrimWhite(&lastoper);
  2095. }
  2096. }
  2097. ajStrTokenDel(&handle);
  2098. ajStrDel(&idstr);
  2099. ajStrDel(&qrystr);
  2100. ajStrDel(&qrystring);
  2101. ajStrDel(&operstr);
  2102. ajStrDel(&lastoper);
  2103. ajStrDel(&qrystring);
  2104. ajQueryTrace(qry);
  2105. accstat = ajTextinAccessFile(textin);
  2106. if(accstat)
  2107. return ajTrue;
  2108. }
  2109. ajErr("Failed to open filename '%S'", qry->Filename);
  2110. return ajFalse;
  2111. }
  2112. else /* dbstat and regstat both failed */
  2113. ajDebug("no filename specified\n");
  2114. ajDebug("\n");
  2115. return ajFalse;
  2116. }
  2117. /* @funcstatic queryRegInit ***************************************************
  2118. **
  2119. ** Initialised regular expressions for parsing queries
  2120. **
  2121. ** @return [void]
  2122. ******************************************************************************/
  2123. static void queryRegInit(void)
  2124. {
  2125. if(queryRegInitDone)
  2126. return;
  2127. if(!queryRegFmt)
  2128. queryRegFmt = ajRegCompC("^([A-Za-z0-9-]*)::(.*)$");
  2129. /* \1 format letters and numbers only */
  2130. /* \2 remainder (filename, etc.)*/
  2131. if(!queryRegSvr)
  2132. queryRegSvr = ajRegCompC("^([A-Za-z][A-Za-z0-9_.]+):");
  2133. /* \1 svrname (start with a letter, then alphanumeric) */
  2134. if(!queryRegDbField)
  2135. queryRegDbField = ajRegCompC("^([A-Za-z][A-Za-z0-9_.]+)([-])"
  2136. "([{])([^}]*)(}?)$");
  2137. if(!queryRegDbId)
  2138. queryRegDbId = ajRegCompC("^([A-Za-z][A-Za-z0-9_.]+)([-]([A-Za-z]+))?"
  2139. "([:]?(([{]?)([^}]*)(}?)))?$");
  2140. /* \1 dbname (start with a letter, then alphanumeric) */
  2141. /* \2 -id or -acc etc. */
  2142. /* \3 qry->Field (id or acc etc.) */
  2143. /* \4 :qrystring or {qrystring}*/
  2144. /* \5 qrystring */
  2145. if(!queryRegFieldId)
  2146. #ifndef WIN32
  2147. /* \1 is filename \3 is the qry->Field \6 is the qrystring */
  2148. queryRegFieldId = ajRegCompC("^(([^{|]+[|])|[^{:]+)"
  2149. ":([^{:]+)"
  2150. "(:)({?)([^}]+)(}?)$");
  2151. #else
  2152. /* Windows file names can start with e.g.: 'C:\' */
  2153. /* But allow e.g. 'C:/...', for Staden spin */
  2154. /* \1 is filename \3 is the qry->Field \6 is the qrystring */
  2155. queryRegFieldId = ajRegCompC ("^(([a-zA-Z]:[\\\\/])?[^{:]+)"
  2156. ":([^{:]+)"
  2157. "(:)({?)([^}]+)(}?)$");
  2158. #endif
  2159. if(!queryRegId)
  2160. #ifndef WIN32
  2161. /* \1 is filename \3 is the qry->Field \6 is the qry->QryString */
  2162. queryRegId = ajRegCompC("^(([^|{]+[|])|[^:{%]+)"
  2163. "([:%]?)(({?)([^}]*)(}?))?$");
  2164. #else
  2165. /* Windows file names can start with e.g.: 'C:\' */
  2166. /* But allow e.g. 'C:/...', for Staden spin */
  2167. /* \1 is filename \6 is the qry->Field \7 is the qry->QryString */
  2168. queryRegId = ajRegCompC ("^(([a-zA-Z]:[\\\\/])?[^:{%]+)"
  2169. "([:%]?)(({?)([^}]*)(}?))?$");
  2170. #endif
  2171. if(!queryRegList) /* \1 is filename \3 is the qry->QryString */
  2172. queryRegList = ajRegCompC("^(@|[Ll][Ii][Ss][Tt]:+)(.+)$");
  2173. if(!queryRegAsis) /* \1 is filename \3 is the qry->QryString */
  2174. queryRegAsis = ajRegCompC("^[Aa][Ss][Ii][Ss]:+(.+)$");
  2175. if(!queryRegWild)
  2176. queryRegWild = ajRegCompC("(.*[*].*)");
  2177. /* \1 wildcard query */
  2178. if(!queryRegRange) /* \1 is rest of USA \2 start \3 end \5 reverse*/
  2179. queryRegRange = ajRegCompC("(.*)[[](-?[0-9]*):(-?[0-9]*)"
  2180. "(:([Rr])?)?[]]$");
  2181. queryRegInitDone = ajTrue;
  2182. return;
  2183. }