/pymol-1.5.0.2/layer0/Word.c

# · C · 1019 lines · 903 code · 75 blank · 41 comment · 298 complexity · 9297fbc3ec1c5d2e23d26cb156565526 MD5 · raw file

  1. /*
  2. A* -------------------------------------------------------------------
  3. B* This file contains source code for the PyMOL computer program
  4. C* Copyright (c) Schrodinger, LLC.
  5. D* -------------------------------------------------------------------
  6. E* It is unlawful to modify or remove this copyright notice.
  7. F* -------------------------------------------------------------------
  8. G* Please see the accompanying LICENSE file for further information.
  9. H* -------------------------------------------------------------------
  10. I* Additional authors of this source file include:
  11. -*
  12. -*
  13. -*
  14. Z* -------------------------------------------------------------------
  15. */
  16. #include"os_python.h"
  17. #include"os_predef.h"
  18. #include"os_std.h"
  19. #include"Base.h"
  20. #include"OOMac.h"
  21. #include"Word.h"
  22. #include"Parse.h"
  23. #include"PyMOLObject.h"
  24. #include"MemoryDebug.h"
  25. struct _CWord {
  26. int no_state_at_present;
  27. };
  28. typedef struct {
  29. int match_mode;
  30. int continued;
  31. int literal1, literal2; /* offsets into charVLA */
  32. int numeric1, numeric2;
  33. int has1, has2;
  34. } MatchNode;
  35. struct _CWordMatcher {
  36. PyMOLGlobals *G;
  37. MatchNode *node;
  38. int n_node;
  39. char *charVLA;
  40. int n_char;
  41. int ignore_case;
  42. };
  43. #define cMatchLiteral 0
  44. #define cMatchNumericRange cWordMatchOptionNumericRanges
  45. #define cMatchAlphaRange cWordMatchOptionAlphaRanges
  46. #define cMatchWildcard 3
  47. #if 0
  48. static void WordMatcherDump(CWordMatcher * I)
  49. {
  50. MatchNode *cur_node = I->node;
  51. register int n_node = I->n_node;
  52. while(n_node--) {
  53. printf("match_mode %d\n", cur_node->match_mode);
  54. printf("literal1 '%s' %d literal2 '%s' %d\n",
  55. I->charVLA + cur_node->literal1,
  56. cur_node->has1, I->charVLA + cur_node->literal2, cur_node->has2);
  57. cur_node++;
  58. }
  59. }
  60. #endif
  61. #ifndef _PYMOL_INLINE
  62. int WordCompare(PyMOLGlobals * G, char *p, char *q, int ignCase)
  63. /* all things equal, shorter is smaller */
  64. {
  65. int result = 0;
  66. register char cp, cq, tlp, tlq;
  67. if(ignCase) {
  68. while((cp = *p) && (cq = *q)) {
  69. p++;
  70. q++;
  71. if(cp != cq) {
  72. (tlp = tolower(cp));
  73. (tlq = tolower(cq));
  74. if(tlp < tlq)
  75. return -1;
  76. else if(tlp > tlq) {
  77. return 1;
  78. }
  79. }
  80. }
  81. } else {
  82. while((cp = *p) && (cq = *q)) {
  83. p++;
  84. q++;
  85. if(cp != cq) {
  86. if(cp < cq) {
  87. return -1;
  88. } else if(cp > cq) {
  89. return 1;
  90. }
  91. }
  92. }
  93. }
  94. if((!result) && (!*p) && (*q))
  95. return -1;
  96. else if((!result) && (*p) && (!*q))
  97. return 1;
  98. return 0;
  99. }
  100. #endif
  101. void WordMatchOptionsConfigInteger(CWordMatchOptions * I)
  102. {
  103. I->range_mode = cWordMatchOptionNumericRanges;
  104. I->lists = true;
  105. I->ignore_case = true;
  106. I->wildcard = 0; /* no wildcard for numbers */
  107. I->allow_hyphen = true;
  108. I->allow_plus = true;
  109. I->space_lists = false;
  110. }
  111. void WordMatchOptionsConfigAlpha(CWordMatchOptions * I, char wildcard, int ignore_case)
  112. {
  113. I->range_mode = cWordMatchOptionAlphaRanges;
  114. I->lists = true;
  115. I->ignore_case = ignore_case;
  116. I->wildcard = wildcard;
  117. I->allow_hyphen = false;
  118. I->allow_plus = false;
  119. I->space_lists = false;
  120. }
  121. void WordMatchOptionsConfigAlphaList(CWordMatchOptions * I, char wildcard,
  122. int ignore_case)
  123. { /* here we expect '+' to be used in lists */
  124. I->range_mode = cWordMatchOptionAlphaRanges;
  125. I->lists = true;
  126. I->ignore_case = ignore_case;
  127. I->wildcard = wildcard;
  128. I->allow_hyphen = false;
  129. I->allow_plus = true;
  130. I->space_lists = false;
  131. }
  132. void WordMatchOptionsConfigMixed(CWordMatchOptions * I, char wildcard, int ignore_case)
  133. {
  134. I->range_mode = cWordMatchOptionNumericRanges;
  135. I->lists = true;
  136. I->ignore_case = ignore_case;
  137. I->wildcard = wildcard;
  138. I->allow_hyphen = true;
  139. I->allow_plus = true;
  140. I->space_lists = false;
  141. }
  142. void WordMatchOptionsConfigNameList(CWordMatchOptions * I, char wildcard, int ignore_case)
  143. {
  144. I->range_mode = cWordMatchOptionAlphaRanges;
  145. I->lists = true;
  146. I->ignore_case = ignore_case;
  147. I->wildcard = wildcard;
  148. I->allow_hyphen = false;
  149. I->allow_plus = false;
  150. I->space_lists = true;
  151. }
  152. CWordMatcher *WordMatcherNew(PyMOLGlobals * G, char *st, CWordMatchOptions * option,
  153. int force)
  154. {
  155. CWordMatcher *result = NULL;
  156. int needed = force;
  157. char wildcard = option->wildcard;
  158. if(wildcard == 32)
  159. wildcard = 0; /* space as wildcard means no wildcard */
  160. if(!st)
  161. return NULL;
  162. { /* first determine if we need to incur the overhead of the matcher */
  163. int escape = false;
  164. char *p = st;
  165. while((*p) && (!needed)) {
  166. if(!escape) {
  167. switch (*p) {
  168. case '\\':
  169. escape = true;
  170. needed = true;
  171. break;
  172. case '+':
  173. if((option->lists) && (option->allow_plus))
  174. needed = true;
  175. break;
  176. case ',': /* list operators */
  177. if(option->lists)
  178. needed = true;
  179. break;
  180. case '-': /* range operators */
  181. if(option->allow_hyphen)
  182. needed = true;
  183. break;
  184. case ':':
  185. if(option->range_mode)
  186. needed = true;
  187. break;
  188. case ' ':
  189. if(option->space_lists)
  190. needed = true;
  191. break;
  192. default:
  193. if(*p == wildcard)
  194. needed = true;
  195. break;
  196. }
  197. } else
  198. escape = false;
  199. p++;
  200. }
  201. }
  202. if(needed) { /* if so, then convert the expression into a match tree */
  203. register int n_char = 0;
  204. register int n_node = 0;
  205. OOCalloc(G, CWordMatcher);
  206. I->charVLA = VLACalloc(char, 10); /* auto_zeroing... */
  207. I->node = VLACalloc(MatchNode, 10);
  208. I->ignore_case = option->ignore_case;
  209. I->G = G;
  210. /* build up the matcher structure... */
  211. {
  212. char *p = st, c, *q;
  213. int escape = false;
  214. int token_active = false;
  215. int node_active = false;
  216. int char_handled = false;
  217. int cur_node = 0;
  218. int expectation = 1;
  219. while(1) {
  220. c = *p;
  221. char_handled = false;
  222. if(!escape) {
  223. switch (c) {
  224. case '\\':
  225. escape = true;
  226. char_handled = true;
  227. break;
  228. case 0:
  229. if(option->lists) {
  230. char_handled = true;
  231. node_active = false;
  232. token_active = false;
  233. }
  234. break;
  235. case '+': /* list operator */
  236. if(option->lists && option->allow_plus) {
  237. if(n_node < expectation) { /* create empty node */
  238. VLACheck(I->node, MatchNode, n_node);
  239. n_node++;
  240. } else {
  241. expectation = n_node + 1;
  242. }
  243. char_handled = true;
  244. node_active = false;
  245. token_active = false;
  246. }
  247. break;
  248. case ',': /* list operator */
  249. if(option->lists) {
  250. if(n_node < expectation) { /* create empty node */
  251. VLACheck(I->node, MatchNode, n_node);
  252. n_node++;
  253. } else {
  254. expectation = n_node + 1;
  255. }
  256. char_handled = true;
  257. node_active = false;
  258. token_active = false;
  259. }
  260. break;
  261. case ' ': /* space list */
  262. if(option->space_lists) {
  263. if(n_node < expectation) { /* create empty node */
  264. VLACheck(I->node, MatchNode, n_node);
  265. n_node++;
  266. } else {
  267. expectation = n_node + 1;
  268. }
  269. char_handled = true;
  270. node_active = false;
  271. token_active = false;
  272. }
  273. break;
  274. case '-': /* range operators */
  275. if(option->allow_hyphen && option->range_mode) {
  276. if(!node_active) {
  277. cur_node = n_node;
  278. VLACheck(I->node, MatchNode, cur_node);
  279. node_active = true;
  280. n_node++;
  281. }
  282. I->node[cur_node].match_mode = option->range_mode;
  283. token_active = false;
  284. char_handled = true;
  285. }
  286. break;
  287. case ':':
  288. if(option->range_mode) {
  289. if(!node_active) {
  290. cur_node = n_node;
  291. VLACheck(I->node, MatchNode, cur_node);
  292. node_active = true;
  293. n_node++;
  294. }
  295. I->node[cur_node].match_mode = option->range_mode;
  296. token_active = false;
  297. char_handled = true;
  298. }
  299. break;
  300. default:
  301. if(c == wildcard) {
  302. if(node_active) {
  303. I->node[cur_node].continued = true;
  304. }
  305. VLACheck(I->node, MatchNode, n_node);
  306. cur_node = n_node;
  307. I->node[cur_node].match_mode = cMatchWildcard;
  308. n_node++;
  309. node_active = true;
  310. token_active = false;
  311. char_handled = true;
  312. }
  313. break;
  314. }
  315. } else
  316. escape = false;
  317. if(!char_handled) {
  318. if(!token_active) {
  319. n_char++;
  320. VLACheck(I->charVLA, char, n_char);
  321. token_active = true;
  322. if((!node_active) || (I->node[cur_node].match_mode == cMatchWildcard)) {
  323. if(node_active) /* must be extending after a wildcard */
  324. I->node[cur_node].continued = true;
  325. else
  326. node_active = true;
  327. VLACheck(I->node, MatchNode, n_node);
  328. cur_node = n_node;
  329. I->node[cur_node].literal1 = n_char; /* the first literal */
  330. n_node++;
  331. } else {
  332. I->node[cur_node].literal2 = n_char; /* must be the second literal */
  333. }
  334. }
  335. /* copy character into auto-terminated string */
  336. VLACheck(I->charVLA, char, n_char + 1);
  337. q = I->charVLA + n_char;
  338. (*q++) = c;
  339. n_char++;
  340. }
  341. if(c)
  342. p++;
  343. else
  344. break;
  345. }
  346. if(n_node < expectation) { /* create empty node */
  347. VLACheck(I->node, MatchNode, n_node);
  348. n_node++;
  349. }
  350. }
  351. {
  352. int a;
  353. int tmp;
  354. MatchNode *node = I->node;
  355. for(a = 0; a < n_node; a++) {
  356. switch (node->match_mode) {
  357. case cMatchLiteral:
  358. if(option->range_mode == cWordMatchOptionNumericRanges) {
  359. if(node->literal1) {
  360. if(sscanf(I->charVLA + node->literal1, "%d", &tmp) == 1) {
  361. node->numeric1 = tmp;
  362. node->has1 = true;
  363. }
  364. }
  365. }
  366. break;
  367. case cMatchAlphaRange:
  368. if(node->literal1)
  369. node->has1 = true;
  370. if(node->literal2)
  371. node->has2 = true;
  372. break;
  373. case cMatchNumericRange:
  374. if(node->literal1) {
  375. if(sscanf(I->charVLA + node->literal1, "%d", &tmp) == 1) {
  376. node->numeric1 = tmp;
  377. node->has1 = true;
  378. }
  379. }
  380. if(node->literal2) {
  381. if(sscanf(I->charVLA + node->literal2, "%d", &tmp) == 1) {
  382. node->numeric2 = tmp;
  383. node->has2 = true;
  384. }
  385. }
  386. break;
  387. }
  388. node++;
  389. }
  390. }
  391. I->n_char = n_char;
  392. I->n_node = n_node;
  393. /* WordMatcherDump(I); */
  394. result = I;
  395. }
  396. return result;
  397. }
  398. static int recursive_match(CWordMatcher * I, MatchNode * cur_node, char *text,
  399. int *value_ptr)
  400. {
  401. int ignore_case = I->ignore_case;
  402. switch (cur_node->match_mode) {
  403. case cMatchLiteral:
  404. {
  405. char *q = I->charVLA + cur_node->literal1;
  406. char *p = text;
  407. while((*p) && (*q)) {
  408. if(*p != *q) {
  409. if(!ignore_case)
  410. return false;
  411. else if(tolower(*p) != tolower(*q))
  412. return false;
  413. }
  414. p++;
  415. q++;
  416. }
  417. if((!(*q)) && (!(*p)))
  418. return true;
  419. if((*p) && (!*q) && cur_node->continued)
  420. return recursive_match(I, cur_node + 1, p, value_ptr);
  421. if((*p) != (*q))
  422. return false;
  423. }
  424. break;
  425. case cMatchWildcard:
  426. {
  427. char *p;
  428. p = text;
  429. if(!cur_node->continued)
  430. return true;
  431. else {
  432. while(*p) {
  433. if(recursive_match(I, cur_node + 1, p, value_ptr))
  434. return 1;
  435. p++;
  436. }
  437. }
  438. }
  439. break;
  440. case cMatchAlphaRange:
  441. {
  442. char *l1 = I->charVLA + cur_node->literal1;
  443. char *l2 = I->charVLA + cur_node->literal2;
  444. if(((!cur_node->has1) ||
  445. (WordCompare(I->G, l1, text, ignore_case) <= 0)) &&
  446. ((!cur_node->has2) || (WordCompare(I->G, l2, text, ignore_case) >= 0)))
  447. return true;
  448. else
  449. return false;
  450. }
  451. break;
  452. case cMatchNumericRange:
  453. if(value_ptr) {
  454. int value = *value_ptr;
  455. if(((!cur_node->has1) ||
  456. (cur_node->numeric1 <= value)) &&
  457. ((!cur_node->has2) || (cur_node->numeric2 >= value)))
  458. return true;
  459. } else {
  460. int value;
  461. if(sscanf(text, "%d", &value) == 1)
  462. if(((!cur_node->has1) ||
  463. (cur_node->numeric1 <= value)) &&
  464. ((!cur_node->has2) || (cur_node->numeric2 >= value)))
  465. return true;
  466. }
  467. break;
  468. }
  469. return false;
  470. }
  471. int WordMatcherMatchAlpha(CWordMatcher * I, char *text)
  472. {
  473. register MatchNode *cur_node = I->node;
  474. register int n_node = I->n_node;
  475. while((n_node--) > 0) {
  476. if(recursive_match(I, cur_node, text, NULL))
  477. return true;
  478. else {
  479. while(cur_node->continued) {
  480. cur_node++;
  481. n_node--;
  482. }
  483. cur_node++;
  484. }
  485. }
  486. return false;
  487. }
  488. int WordMatcherMatchMixed(CWordMatcher * I, char *text, int value)
  489. {
  490. register MatchNode *cur_node = I->node;
  491. register int n_node = I->n_node;
  492. while((n_node--) > 0) {
  493. if(recursive_match(I, cur_node, text, &value))
  494. return true;
  495. else {
  496. while(cur_node->continued) {
  497. cur_node++;
  498. n_node--;
  499. }
  500. cur_node++;
  501. }
  502. }
  503. return false;
  504. }
  505. static int integer_match(CWordMatcher * I, MatchNode * cur_node, int value)
  506. {
  507. switch (cur_node->match_mode) {
  508. case cMatchLiteral:
  509. if((cur_node->has1) && (cur_node->numeric1 == value))
  510. return true;
  511. break;
  512. case cMatchNumericRange:
  513. if(((!cur_node->has1) ||
  514. (cur_node->numeric1 <= value)) &&
  515. ((!cur_node->has2) || (cur_node->numeric2 >= value)))
  516. return true;
  517. break;
  518. }
  519. return false;
  520. }
  521. int WordMatcherMatchInteger(CWordMatcher * I, int value)
  522. {
  523. register MatchNode *cur_node = I->node;
  524. register int n_node = I->n_node;
  525. while((n_node--) > 0) {
  526. if(integer_match(I, cur_node, value))
  527. return true;
  528. else {
  529. while(cur_node->continued) {
  530. cur_node++;
  531. n_node--;
  532. }
  533. cur_node++;
  534. }
  535. }
  536. return false;
  537. }
  538. void WordMatcherFree(CWordMatcher * I)
  539. {
  540. if(I) {
  541. VLAFreeP(I->node);
  542. VLAFreeP(I->charVLA);
  543. }
  544. OOFreeP(I);
  545. }
  546. CWordList *WordListNew(PyMOLGlobals * G, char *st)
  547. {
  548. int n_word = 0;
  549. char *p;
  550. int len = 0;
  551. OOCalloc(G, CWordList);
  552. if(I) {
  553. p = st;
  554. /* first, count how many words we have */
  555. while(*p) {
  556. if(*p > 32) {
  557. n_word++;
  558. while((*p) > 32) {
  559. len++;
  560. p++;
  561. }
  562. len++;
  563. } else
  564. p++;
  565. }
  566. /* allocate the storage we'll need to hold the words */
  567. {
  568. I->word = Alloc(char, len);
  569. I->start = Alloc(char *, n_word);
  570. /* and copy the words */
  571. if(I->word && I->start) {
  572. char *q = I->word;
  573. char **q_ptr = I->start;
  574. p = st;
  575. while(*p) {
  576. if(*p > 32) {
  577. *(q_ptr++) = q;
  578. while((*p) > 32) {
  579. *(q++) = *(p++);
  580. }
  581. *(q++) = 0;
  582. len++;
  583. } else
  584. p++;
  585. }
  586. I->n_word = n_word;
  587. }
  588. }
  589. }
  590. return I;
  591. }
  592. void WordListFreeP(CWordList * I)
  593. {
  594. if(I) {
  595. FreeP(I->word);
  596. FreeP(I->start);
  597. FreeP(I);
  598. }
  599. }
  600. void WordListDump(CWordList * I, char *prefix)
  601. {
  602. if(I) {
  603. int a;
  604. printf(" %s: n_word %d\n", prefix, I->n_word);
  605. for(a = 0; a < I->n_word; a++) {
  606. printf(" %s: word %d=[%s]\n", prefix, a, I->start[a]);
  607. }
  608. }
  609. }
  610. int WordListIterate(PyMOLGlobals * G, CWordList * I, char **ptr, int *hidden)
  611. {
  612. int result = true;
  613. if(*hidden >= 0) {
  614. if(*hidden < I->n_word) {
  615. (*ptr) = I->start[(*hidden)++];
  616. } else {
  617. result = false;
  618. }
  619. }
  620. return result;
  621. }
  622. int WordListMatch(PyMOLGlobals * G, CWordList * I, char *name, int ignore_case)
  623. {
  624. int result = -1;
  625. if(I) {
  626. int a;
  627. for(a = 0; a < I->n_word; a++) {
  628. if(WordMatch(G, I->start[a], name, ignore_case)) {
  629. result = a;
  630. break;
  631. }
  632. }
  633. }
  634. return result;
  635. }
  636. int WordInit(PyMOLGlobals * G)
  637. {
  638. register CWord *I = NULL;
  639. I = (G->Word = Calloc(CWord, 1));
  640. if(I) {
  641. return 1;
  642. } else
  643. return 0;
  644. }
  645. void WordFree(PyMOLGlobals * G)
  646. {
  647. FreeP(G->Word);
  648. }
  649. void WordPrimeCommaMatch(PyMOLGlobals * G, char *p)
  650. { /* replace '+' with ',' */
  651. while(*p) { /* this should not be done here... */
  652. if(*p == '+')
  653. if(!((*(p + 1) == 0) || (*(p + 1) == ',') || (*(p + 1) == '+')))
  654. *p = ',';
  655. p++;
  656. }
  657. }
  658. int WordMatchExact(PyMOLGlobals * G, char *p, char *q, int ignCase)
  659. /* 0 = no match
  660. non-zero = perfect match */
  661. {
  662. while((*p) && (*q)) {
  663. if(*p != *q) {
  664. if(!ignCase)
  665. return 0;
  666. else if(tolower(*p) != tolower(*q))
  667. return 0;
  668. }
  669. p++;
  670. q++;
  671. }
  672. if((*p) != (*q))
  673. return 0;
  674. return 1;
  675. }
  676. int WordMatchNoWild(PyMOLGlobals * G, char *p, char *q, int ignCase)
  677. /* allows for p to match when shorter than q.
  678. Returns:
  679. 0 = no match
  680. positive = match out to N characters
  681. negative = perfect match */
  682. {
  683. int i = 1;
  684. while((*p) && (*q)) {
  685. if(*p != *q) {
  686. if(ignCase) {
  687. if(tolower(*p) != tolower(*q)) {
  688. i = 0;
  689. break;
  690. }
  691. } else {
  692. i = 0;
  693. break;
  694. }
  695. }
  696. i++;
  697. p++;
  698. q++;
  699. }
  700. if((*p) && (!*q))
  701. i = 0;
  702. if(i && ((!*p) && (!*q))) /*exact match gives negative value */
  703. i = -i;
  704. return (i);
  705. }
  706. int WordMatch(PyMOLGlobals * G, char *p, char *q, int ignCase)
  707. /* allows for terminal wildcard (*) in p
  708. * and allows for p to match when shorter than q.
  709. Returns:
  710. 0 = no match
  711. positive = match out to N characters
  712. negative = perfect/wildcard match */
  713. {
  714. int i = 1;
  715. register char WILDCARD = '*';
  716. while((*p) && (*q)) {
  717. if(*p != *q) {
  718. if(*p == WILDCARD) {
  719. i = -i;
  720. break;
  721. }
  722. if(ignCase) {
  723. if(tolower(*p) != tolower(*q)) {
  724. i = 0;
  725. break;
  726. }
  727. } else {
  728. i = 0;
  729. break;
  730. }
  731. }
  732. i++;
  733. p++;
  734. q++;
  735. }
  736. if((!*q) && (*p == WILDCARD))
  737. i = -i;
  738. if(*p != WILDCARD) {
  739. if((*p) && (!*q))
  740. i = 0;
  741. }
  742. if(i && ((!*p) && (!*q))) /*exact match gives negative value */
  743. i = -i;
  744. return (i);
  745. }
  746. int WordMatchComma(PyMOLGlobals * G, char *pp, char *qq, int ignCase)
  747. /* allows for comma list in p, also allows wildcards (*) in p */
  748. {
  749. register char *p = pp, *q = qq;
  750. register int i = 0;
  751. register char WILDCARD = '*';
  752. register char pc, qc;
  753. register int ic = ignCase;
  754. int best_i = 0;
  755. char *q_copy;
  756. int blank;
  757. int trailing_comma = 0;
  758. blank = (!*p);
  759. q_copy = q;
  760. while(((*p) || (blank)) && (best_i >= 0)) {
  761. blank = 0;
  762. i = 1;
  763. q = q_copy;
  764. while((pc = (*p)) && (qc = (*q))) {
  765. if(pc == ',')
  766. break;
  767. if(pc != qc) {
  768. if(pc == WILDCARD) {
  769. i = -i;
  770. break;
  771. }
  772. if(ic) {
  773. if(tolower(pc) != tolower(qc)) {
  774. i = 0;
  775. break;
  776. }
  777. } else {
  778. i = 0;
  779. break;
  780. }
  781. }
  782. p++;
  783. q++;
  784. i++;
  785. }
  786. if((!*q) && ((*p == WILDCARD) || (*p == ',')))
  787. i = -i;
  788. if((*p != WILDCARD) && (*p != ','))
  789. if((*p) && (!*q))
  790. i = 0;
  791. if(i && ((!*p) && (!*q))) /*exact match */
  792. i = -i;
  793. if(i < 0)
  794. best_i = i;
  795. else if((best_i >= 0))
  796. if(i > best_i)
  797. best_i = i;
  798. if(best_i >= 0) {
  799. while(*p) {
  800. if(*p == ',')
  801. break;
  802. p++;
  803. }
  804. if(*p == ',') { /* handle special case, trailing comma */
  805. if(*(p + 1))
  806. p++;
  807. else if(!trailing_comma)
  808. trailing_comma = 1;
  809. else
  810. p++;
  811. }
  812. }
  813. }
  814. return (best_i);
  815. }
  816. int WordMatchCommaExact(PyMOLGlobals * G, char *p, char *q, int ignCase)
  817. /* allows for comma list in p, no wildcards */
  818. {
  819. int i = 0;
  820. int best_i = 0;
  821. char *q_copy;
  822. int blank;
  823. int trailing_comma = 0;
  824. /* printf("match? [%s] [%s] ",p,q); */
  825. blank = (!*p);
  826. q_copy = q;
  827. while(((*p) || (blank)) && (best_i >= 0)) {
  828. blank = 0;
  829. i = 1;
  830. q = q_copy;
  831. while((*p) && (*q)) {
  832. if(*p == ',')
  833. break;
  834. if(*p != *q) {
  835. if(ignCase) {
  836. if(tolower(*p) != tolower(*q)) {
  837. i = 0;
  838. break;
  839. }
  840. } else {
  841. i = 0;
  842. break;
  843. }
  844. }
  845. i++;
  846. p++;
  847. q++;
  848. }
  849. if((!*q) && (*p == ','))
  850. i = -i;
  851. if(*p != ',')
  852. if((*p) && (!*q))
  853. i = 0;
  854. if(i && ((!*p) && (!*q))) /*exact match */
  855. i = -i;
  856. if(i < 0)
  857. best_i = i;
  858. else if((best_i >= 0))
  859. if(i > best_i)
  860. best_i = i;
  861. if(best_i >= 0) {
  862. while(*p) {
  863. if(*p == ',')
  864. break;
  865. p++;
  866. }
  867. if(*p == ',') { /* handle special case, trailing comma */
  868. if(*(p + 1))
  869. p++;
  870. else if(!trailing_comma)
  871. trailing_comma = 1;
  872. else
  873. p++;
  874. }
  875. }
  876. }
  877. /* printf("result: %d\n",best_i); */
  878. return (best_i);
  879. }
  880. int WordMatchCommaInt(PyMOLGlobals * G, char *p, int number)
  881. {
  882. WordType buffer;
  883. sprintf(buffer, "%d", number);
  884. return (WordMatchComma(G, p, buffer, 1));
  885. }
  886. int WordIndex(PyMOLGlobals * G, WordType * list, char *word, int minMatch, int ignCase)
  887. {
  888. int c, i, mi, mc;
  889. int result = -1;
  890. c = 0;
  891. mc = -1;
  892. mi = -1;
  893. while(list[c][0]) {
  894. i = WordMatch(G, word, list[c], ignCase);
  895. if(i > 0) {
  896. if(mi < i) {
  897. mi = i;
  898. mc = c;
  899. }
  900. } else if(i < 0) {
  901. if((-i) < minMatch)
  902. mi = minMatch + 1; /*exact match always matches */
  903. else
  904. mi = (-i);
  905. mc = c;
  906. }
  907. c++;
  908. }
  909. if((mi > minMatch))
  910. result = mc;
  911. return (result);
  912. }
  913. int WordKey(PyMOLGlobals * G, WordKeyValue * list, char *word, int minMatch, int ignCase,
  914. int *exact)
  915. {
  916. int c, i, mi, mc;
  917. int result = 0;
  918. c = 0;
  919. mc = -1;
  920. mi = -1;
  921. *exact = false;
  922. while(list[c].word[0]) {
  923. i = WordMatchNoWild(G, word, list[c].word, ignCase);
  924. if(i > 0) {
  925. if(mi < i) {
  926. mi = i;
  927. mc = list[c].value;
  928. }
  929. } else if(i < 0) {
  930. *exact = true;
  931. if((-i) <= minMatch) {
  932. mi = minMatch + 1; /*exact match always matches */
  933. } else
  934. mi = (-i);
  935. mc = list[c].value;
  936. }
  937. c++;
  938. }
  939. if((mi >= minMatch))
  940. result = mc;
  941. return (result);
  942. }