You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

842 lines
24 KiB

  1. /**
  2. @file
  3. @ingroup mtr
  4. @brief Functions to support group specification for reordering.
  5. @see cudd package
  6. @author Fabio Somenzi
  7. @copyright@parblock
  8. Copyright (c) 1995-2015, Regents of the University of Colorado
  9. All rights reserved.
  10. Redistribution and use in source and binary forms, with or without
  11. modification, are permitted provided that the following conditions
  12. are met:
  13. Redistributions of source code must retain the above copyright
  14. notice, this list of conditions and the following disclaimer.
  15. Redistributions in binary form must reproduce the above copyright
  16. notice, this list of conditions and the following disclaimer in the
  17. documentation and/or other materials provided with the distribution.
  18. Neither the name of the University of Colorado nor the names of its
  19. contributors may be used to endorse or promote products derived from
  20. this software without specific prior written permission.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. POSSIBILITY OF SUCH DAMAGE.
  33. @endparblock
  34. */
  35. #include "util.h"
  36. #include "mtrInt.h"
  37. /*---------------------------------------------------------------------------*/
  38. /* Constant declarations */
  39. /*---------------------------------------------------------------------------*/
  40. /*---------------------------------------------------------------------------*/
  41. /* Stucture declarations */
  42. /*---------------------------------------------------------------------------*/
  43. /*---------------------------------------------------------------------------*/
  44. /* Type declarations */
  45. /*---------------------------------------------------------------------------*/
  46. /*---------------------------------------------------------------------------*/
  47. /* Variable declarations */
  48. /*---------------------------------------------------------------------------*/
  49. /*---------------------------------------------------------------------------*/
  50. /* Macro declarations */
  51. /*---------------------------------------------------------------------------*/
  52. /** \cond */
  53. /*---------------------------------------------------------------------------*/
  54. /* Static function prototypes */
  55. /*---------------------------------------------------------------------------*/
  56. static int mtrShiftHL (MtrNode *node, int shift);
  57. /** \endcond */
  58. /*---------------------------------------------------------------------------*/
  59. /* Definition of exported functions */
  60. /*---------------------------------------------------------------------------*/
  61. /**
  62. @brief Allocate new tree.
  63. @details Allocate new tree with one node, whose low and size
  64. fields are specified by the lower and size parameters.
  65. @return pointer to tree root.
  66. @sideeffect None
  67. @see Mtr_InitTree Mtr_FreeTree
  68. */
  69. MtrNode *
  70. Mtr_InitGroupTree(
  71. int lower,
  72. int size)
  73. {
  74. MtrNode *root;
  75. root = Mtr_InitTree();
  76. if (root == NULL) return(NULL);
  77. root->flags = MTR_DEFAULT;
  78. root->low = lower;
  79. root->size = size;
  80. return(root);
  81. } /* end of Mtr_InitGroupTree */
  82. /**
  83. @brief Makes a new group with size leaves starting at low.
  84. @details If the new group intersects an existing group, it must
  85. either contain it or be contained by it. This procedure relies on
  86. the low and size fields of each node. It also assumes that the
  87. children of each node are sorted in order of increasing low. In
  88. case of a valid request, the flags of the new group are set to the
  89. value passed in `flags.'
  90. @return the pointer to the root of the new group upon successful
  91. termination; NULL otherwise. If the group already exists, the
  92. pointer to its root is returned.
  93. @sideeffect None
  94. @see Mtr_DissolveGroup Mtr_ReadGroups Mtr_FindGroup
  95. */
  96. MtrNode *
  97. Mtr_MakeGroup(
  98. MtrNode * root /**< root of the group tree */,
  99. unsigned int low /**< lower bound of the group */,
  100. unsigned int size /**< size of the group */,
  101. unsigned int flags /**< flags for the new group */)
  102. {
  103. MtrNode *node,
  104. *first,
  105. *last,
  106. *previous,
  107. *newn;
  108. /* Sanity check. */
  109. if (size == 0)
  110. return(NULL);
  111. /* Check whether current group includes new group. This check is
  112. ** necessary at the top-level call. In the subsequent calls it is
  113. ** redundant. */
  114. if (low < (unsigned int) root->low ||
  115. low + size > (unsigned int) (root->low + root->size))
  116. return(NULL);
  117. /* At this point we know that the new group is contained
  118. ** in the group of root. We have two possible cases here:
  119. ** - root is a terminal node;
  120. ** - root has children. */
  121. /* Root has no children: create a new group. */
  122. if (root->child == NULL) {
  123. newn = Mtr_AllocNode();
  124. if (newn == NULL) return(NULL); /* out of memory */
  125. newn->low = low;
  126. newn->size = size;
  127. newn->flags = flags;
  128. newn->parent = root;
  129. newn->elder = newn->younger = newn->child = NULL;
  130. root->child = newn;
  131. return(newn);
  132. }
  133. /* Root has children: Find all children of root that are included
  134. ** in the new group. If the group of any child entirely contains
  135. ** the new group, call Mtr_MakeGroup recursively. */
  136. previous = NULL;
  137. first = root->child; /* guaranteed to be non-NULL */
  138. while (first != NULL && low >= (unsigned int) (first->low + first->size)) {
  139. previous = first;
  140. first = first->younger;
  141. }
  142. if (first == NULL) {
  143. /* We have scanned the entire list and we need to append a new
  144. ** child at the end of it. Previous points to the last child
  145. ** of root. */
  146. newn = Mtr_AllocNode();
  147. if (newn == NULL) return(NULL); /* out of memory */
  148. newn->low = low;
  149. newn->size = size;
  150. newn->flags = flags;
  151. newn->parent = root;
  152. newn->elder = previous;
  153. previous->younger = newn;
  154. newn->younger = newn->child = NULL;
  155. return(newn);
  156. }
  157. /* Here first is non-NULL and low < first->low + first->size. */
  158. if (low >= (unsigned int) first->low &&
  159. low + size <= (unsigned int) (first->low + first->size)) {
  160. /* The new group is contained in the group of first. */
  161. newn = Mtr_MakeGroup(first, low, size, flags);
  162. return(newn);
  163. } else if (low + size <= first->low) {
  164. /* The new group is entirely contained in the gap between
  165. ** previous and first. */
  166. newn = Mtr_AllocNode();
  167. if (newn == NULL) return(NULL); /* out of memory */
  168. newn->low = low;
  169. newn->size = size;
  170. newn->flags = flags;
  171. newn->child = NULL;
  172. newn->parent = root;
  173. newn->elder = previous;
  174. newn->younger = first;
  175. first->elder = newn;
  176. if (previous != NULL) {
  177. previous->younger = newn;
  178. } else {
  179. root->child = newn;
  180. }
  181. return(newn);
  182. } else if (low < (unsigned int) first->low &&
  183. low + size < (unsigned int) (first->low + first->size)) {
  184. /* Trying to cut an existing group: not allowed. */
  185. return(NULL);
  186. } else if (low > first->low) {
  187. /* The new group neither is contained in the group of first
  188. ** (this was tested above) nor contains it. It is therefore
  189. ** trying to cut an existing group: not allowed. */
  190. return(NULL);
  191. }
  192. /* First holds the pointer to the first child contained in the new
  193. ** group. Here low <= first->low and low + size >= first->low +
  194. ** first->size. One of the two inequalities is strict. */
  195. last = first;
  196. while (last->younger != NULL &&
  197. (unsigned int) (last->younger->low + last->younger->size) <= low + size) {
  198. last = last->younger;
  199. }
  200. if (last == NULL) {
  201. /* All the chilren of root from first onward become children
  202. ** of the new group. */
  203. newn = Mtr_AllocNode();
  204. if (newn == NULL) return(NULL); /* out of memory */
  205. newn->low = low;
  206. newn->size = size;
  207. newn->flags = flags;
  208. newn->child = first;
  209. newn->parent = root;
  210. newn->elder = previous;
  211. newn->younger = NULL;
  212. first->elder = NULL;
  213. if (previous != NULL) {
  214. previous->younger = newn;
  215. } else {
  216. root->child = newn;
  217. }
  218. last = first;
  219. while (last != NULL) {
  220. last->parent = newn;
  221. last = last->younger;
  222. }
  223. return(newn);
  224. }
  225. /* Here last != NULL and low + size <= last->low + last->size. */
  226. if (low + size - 1 >= (unsigned int) last->low &&
  227. low + size < (unsigned int) (last->low + last->size)) {
  228. /* Trying to cut an existing group: not allowed. */
  229. return(NULL);
  230. }
  231. /* First and last point to the first and last of the children of
  232. ** root that are included in the new group. Allocate a new node
  233. ** and make all children of root between first and last chidren of
  234. ** the new node. Previous points to the child of root immediately
  235. ** preceeding first. If it is NULL, then first is the first child
  236. ** of root. */
  237. newn = Mtr_AllocNode();
  238. if (newn == NULL) return(NULL); /* out of memory */
  239. newn->low = low;
  240. newn->size = size;
  241. newn->flags = flags;
  242. newn->child = first;
  243. newn->parent = root;
  244. if (previous == NULL) {
  245. root->child = newn;
  246. } else {
  247. previous->younger = newn;
  248. }
  249. newn->elder = previous;
  250. newn->younger = last->younger;
  251. if (last->younger != NULL) {
  252. last->younger->elder = newn;
  253. }
  254. last->younger = NULL;
  255. first->elder = NULL;
  256. for (node = first; node != NULL; node = node->younger) {
  257. node->parent = newn;
  258. }
  259. return(newn);
  260. } /* end of Mtr_MakeGroup */
  261. /**
  262. @brief Merges the children of `group' with the children of its
  263. parent.
  264. @details Disposes of the node pointed by group. If group is the root
  265. of the group tree, this procedure leaves the tree unchanged.
  266. @return the pointer to the parent of `group' upon successful
  267. termination; NULL otherwise.
  268. @sideeffect None
  269. @see Mtr_MakeGroup
  270. */
  271. MtrNode *
  272. Mtr_DissolveGroup(
  273. MtrNode * group /**< group to be dissolved */)
  274. {
  275. MtrNode *parent;
  276. MtrNode *last;
  277. parent = group->parent;
  278. if (parent == NULL) return(NULL);
  279. if (MTR_TEST(group,MTR_TERMINAL) || group->child == NULL) return(NULL);
  280. /* Make all children of group children of its parent, and make
  281. ** last point to the last child of group. */
  282. for (last = group->child; last->younger != NULL; last = last->younger) {
  283. last->parent = parent;
  284. }
  285. last->parent = parent;
  286. last->younger = group->younger;
  287. if (group->younger != NULL) {
  288. group->younger->elder = last;
  289. }
  290. group->child->elder = group->elder;
  291. if (group == parent->child) {
  292. parent->child = group->child;
  293. } else {
  294. group->elder->younger = group->child;
  295. }
  296. Mtr_DeallocNode(group);
  297. return(parent);
  298. } /* end of Mtr_DissolveGroup */
  299. /**
  300. @brief Finds a group with size leaves starting at low, if it exists.
  301. @details This procedure relies on the low and size fields of each
  302. node. It also assumes that the children of each node are sorted in
  303. order of increasing low.
  304. @return the pointer to the root of the group upon successful
  305. termination; NULL otherwise.
  306. @sideeffect None
  307. */
  308. MtrNode *
  309. Mtr_FindGroup(
  310. MtrNode * root /**< root of the group tree */,
  311. unsigned int low /**< lower bound of the group */,
  312. unsigned int size /**< upper bound of the group */)
  313. {
  314. MtrNode *node;
  315. #ifdef MTR_DEBUG
  316. /* We cannot have a non-empty proper subgroup of a singleton set. */
  317. assert(!MTR_TEST(root,MTR_TERMINAL));
  318. #endif
  319. /* Sanity check. */
  320. if (size < 1) return(NULL);
  321. /* Check whether current group includes the group sought. This
  322. ** check is necessary at the top-level call. In the subsequent
  323. ** calls it is redundant. */
  324. if (low < (unsigned int) root->low ||
  325. low + size > (unsigned int) (root->low + root->size))
  326. return(NULL);
  327. if (root->size == size && root->low == low)
  328. return(root);
  329. if (root->child == NULL)
  330. return(NULL);
  331. /* Find all chidren of root that are included in the new group. If
  332. ** the group of any child entirely contains the new group, call
  333. ** Mtr_MakeGroup recursively. */
  334. node = root->child;
  335. while (low >= (unsigned int) (node->low + node->size)) {
  336. node = node->younger;
  337. }
  338. if (low + size <= (unsigned int) (node->low + node->size)) {
  339. /* The group is contained in the group of node. */
  340. node = Mtr_FindGroup(node, low, size);
  341. return(node);
  342. } else {
  343. return(NULL);
  344. }
  345. } /* end of Mtr_FindGroup */
  346. /**
  347. @brief Swaps two children of a tree node.
  348. @details Adjusts the high and low fields of the two nodes and their
  349. descendants. The two children must be adjacent. However, first may
  350. be the younger sibling of second.
  351. @return 1 in case of success; 0 otherwise.
  352. @sideeffect None
  353. */
  354. int
  355. Mtr_SwapGroups(
  356. MtrNode * first /**< first node to be swapped */,
  357. MtrNode * second /**< second node to be swapped */)
  358. {
  359. MtrNode *node;
  360. MtrNode *parent;
  361. int sizeFirst;
  362. int sizeSecond;
  363. if (second->younger == first) { /* make first first */
  364. node = first;
  365. first = second;
  366. second = node;
  367. } else if (first->younger != second) { /* non-adjacent */
  368. return(0);
  369. }
  370. sizeFirst = first->size;
  371. sizeSecond = second->size;
  372. /* Swap the two nodes. */
  373. parent = first->parent;
  374. if (parent == NULL || second->parent != parent) return(0);
  375. if (parent->child == first) {
  376. parent->child = second;
  377. } else { /* first->elder != NULL */
  378. first->elder->younger = second;
  379. }
  380. if (second->younger != NULL) {
  381. second->younger->elder = first;
  382. }
  383. first->younger = second->younger;
  384. second->elder = first->elder;
  385. first->elder = second;
  386. second->younger = first;
  387. /* Adjust the high and low fields. */
  388. if (!mtrShiftHL(first,sizeSecond)) return(0);
  389. if (!mtrShiftHL(second,-sizeFirst)) return(0);
  390. return(1);
  391. } /* end of Mtr_SwapGroups */
  392. /**
  393. @brief Fix variable tree at the end of tree sifting.
  394. @details Fix the levels in the variable tree sorting siblings
  395. according to them. It should be called on a non-NULL tree. It then
  396. maintains this invariant. It applies insertion sorting to the list of
  397. siblings The order is determined by permutation, which is used to find
  398. the new level of the node index. Index must refer to the first variable
  399. in the group.
  400. @sideeffect The tree is modified.
  401. */
  402. void
  403. Mtr_ReorderGroups(
  404. MtrNode *treenode,
  405. int *permutation)
  406. {
  407. MtrNode *auxnode;
  408. /* Initialize sorted list to first element. */
  409. MtrNode *sorted = treenode;
  410. sorted->low = permutation[sorted->index];
  411. if (sorted->child != NULL)
  412. Mtr_ReorderGroups(sorted->child, permutation);
  413. auxnode = treenode->younger;
  414. while (auxnode != NULL) {
  415. MtrNode *rightplace;
  416. MtrNode *moving = auxnode;
  417. auxnode->low = permutation[auxnode->index];
  418. if (auxnode->child != NULL)
  419. Mtr_ReorderGroups(auxnode->child, permutation);
  420. rightplace = auxnode->elder;
  421. /* Find insertion point. */
  422. while (rightplace != NULL && auxnode->low < rightplace->low)
  423. rightplace = rightplace->elder;
  424. auxnode = auxnode->younger;
  425. if (auxnode != NULL) {
  426. auxnode->elder = moving->elder;
  427. auxnode->elder->younger = auxnode;
  428. } else {
  429. moving->elder->younger = NULL;
  430. }
  431. if (rightplace == NULL) { /* Move to head of sorted list. */
  432. sorted->elder = moving;
  433. moving->elder = NULL;
  434. moving->younger = sorted;
  435. sorted = moving;
  436. } else { /* Splice. */
  437. moving->elder = rightplace;
  438. moving->younger = rightplace->younger;
  439. if (rightplace->younger != NULL)
  440. rightplace->younger->elder = moving;
  441. rightplace->younger = moving;
  442. }
  443. }
  444. /* Fix parent. */
  445. if (sorted->parent != NULL)
  446. sorted->parent->child = sorted;
  447. } /* end of Mtr_ReorderGroups */
  448. /**
  449. @brief Prints the groups as a parenthesized list.
  450. @details After each group, the group's flag are printed, preceded by a `|'.
  451. For each flag (except MTR_TERMINAL) a character is printed.
  452. <ul>
  453. <li>F: MTR_FIXED
  454. <li>N: MTR_NEWNODE
  455. <li>S: MTR_SOFT
  456. </ul>
  457. The second argument, silent, if different from 0, causes
  458. Mtr_PrintGroups to only check the syntax of the group tree.
  459. @sideeffect None
  460. @see Mtr_PrintTree
  461. */
  462. void
  463. Mtr_PrintGroups(
  464. MtrNode const * root /**< root of the group tree */,
  465. int silent /**< flag to check tree syntax only */)
  466. {
  467. MtrNode *node;
  468. assert(root != NULL);
  469. assert(root->younger == NULL || root->younger->elder == root);
  470. assert(root->elder == NULL || root->elder->younger == root);
  471. #if SIZEOF_VOID_P == 8
  472. if (!silent) (void) printf("(%u",root->low);
  473. #else
  474. if (!silent) (void) printf("(%hu",root->low);
  475. #endif
  476. if (MTR_TEST(root,MTR_TERMINAL) || root->child == NULL) {
  477. if (!silent) (void) printf(",");
  478. } else {
  479. node = root->child;
  480. while (node != NULL) {
  481. assert(node->low >= root->low && (int) (node->low + node->size) <= (int) (root->low + root->size));
  482. assert(node->parent == root);
  483. Mtr_PrintGroups(node,silent);
  484. node = node->younger;
  485. }
  486. }
  487. if (!silent) {
  488. #if SIZEOF_VOID_P == 8
  489. (void) printf("%u", (MtrHalfWord) (root->low + root->size - 1));
  490. #else
  491. (void) printf("%hu", (MtrHalfWord) (root->low + root->size - 1));
  492. #endif
  493. if (root->flags != MTR_DEFAULT) {
  494. (void) printf("|");
  495. if (MTR_TEST(root,MTR_FIXED)) (void) printf("F");
  496. if (MTR_TEST(root,MTR_NEWNODE)) (void) printf("N");
  497. if (MTR_TEST(root,MTR_SOFT)) (void) printf("S");
  498. }
  499. (void) printf(")");
  500. if (root->parent == NULL) (void) printf("\n");
  501. }
  502. assert((root->flags &~(MTR_TERMINAL | MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
  503. return;
  504. } /* end of Mtr_PrintGroups */
  505. /**
  506. @brief Prints the variable order as a parenthesized list.
  507. @details After each group, the group's flag are printed, preceded by a `|'.
  508. For each flag (except MTR_TERMINAL) a character is printed.
  509. <ul>
  510. <li>F: MTR_FIXED
  511. <li>N: MTR_NEWNODE
  512. <li>S: MTR_SOFT
  513. </ul>
  514. The second argument, gives the map from levels to variable indices.
  515. @return 1 if successful; 0 otherwise.
  516. @sideeffect None
  517. @see Mtr_PrintGroups
  518. */
  519. int
  520. Mtr_PrintGroupedOrder(
  521. MtrNode const * root /**< root of the group tree */,
  522. int const *invperm /**< map from levels to indices */,
  523. FILE *fp /**< output file */)
  524. {
  525. MtrNode *child;
  526. MtrHalfWord level;
  527. int retval;
  528. assert(root != NULL);
  529. assert(root->younger == NULL || root->younger->elder == root);
  530. assert(root->elder == NULL || root->elder->younger == root);
  531. retval = fprintf(fp,"(");
  532. if (retval == EOF) return(0);
  533. level = root->low;
  534. child = root->child;
  535. while (child != NULL) {
  536. assert(child->low >= root->low && (child->low + child->size) <= (root->low + root->size));
  537. assert(child->parent == root);
  538. while (level < child->low) {
  539. retval = fprintf(fp,"%d%s", invperm[level], (level < root->low + root->size - 1) ? "," : "");
  540. if (retval == EOF) return(0);
  541. level++;
  542. }
  543. retval = Mtr_PrintGroupedOrder(child,invperm,fp);
  544. if (retval == 0) return(0);
  545. level += child->size;
  546. if (level < root->low + root->size - 1) {
  547. retval = fprintf(fp,",");
  548. if (retval == EOF) return(0);
  549. }
  550. child = child->younger;
  551. }
  552. while (level < root->low + root->size) {
  553. retval = fprintf(fp,"%d%s", invperm[level], (level < root->low + root->size - 1) ? "," : "");
  554. if (retval == EOF) return(0);
  555. level++;
  556. }
  557. if (root->flags != MTR_DEFAULT) {
  558. retval = fprintf(fp,"|");
  559. if (retval == EOF) return(0);
  560. if (MTR_TEST(root,MTR_FIXED)) {
  561. retval = fprintf(fp,"F");
  562. if (retval == EOF) return(0);
  563. }
  564. if (MTR_TEST(root,MTR_NEWNODE)) {
  565. retval = fprintf(fp,"N");
  566. if (retval == EOF) return(0);
  567. }
  568. if (MTR_TEST(root,MTR_SOFT)) {
  569. retval = fprintf(fp,"S");
  570. if (retval == EOF) return(0);
  571. }
  572. }
  573. retval = fprintf(fp,")");
  574. if (retval == EOF) return(0);
  575. if (root->parent == NULL) {
  576. retval = fprintf(fp,"\n");
  577. if (retval == EOF) return(0);
  578. }
  579. assert((root->flags &~(MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
  580. return(1);
  581. } /* end of Mtr_PrintGroupedOrder */
  582. /**
  583. @brief Reads groups from a file and creates a group tree.
  584. @details Each group is specified by three fields:
  585. low size flags.
  586. Low and size are (short) integers. Flags is a string composed of the
  587. following characters (with associated translation):
  588. <ul>
  589. <li>D: MTR_DEFAULT
  590. <li>F: MTR_FIXED
  591. <li>N: MTR_NEWNODE
  592. <li>S: MTR_SOFT
  593. <li>T: MTR_TERMINAL
  594. </ul>
  595. Normally, the only flags that are needed are D and F. Groups and
  596. fields are separated by white space (spaces, tabs, and newlines).
  597. @return a pointer to the group tree if successful; NULL otherwise.
  598. @sideeffect None
  599. @see Mtr_InitGroupTree Mtr_MakeGroup
  600. */
  601. MtrNode *
  602. Mtr_ReadGroups(
  603. FILE * fp /**< file pointer */,
  604. int nleaves /**< number of leaves of the new tree */)
  605. {
  606. int low;
  607. int size;
  608. int err;
  609. unsigned int flags;
  610. MtrNode *root;
  611. MtrNode *node;
  612. char attrib[8*sizeof(unsigned int)+1];
  613. char *c;
  614. root = Mtr_InitGroupTree(0,nleaves);
  615. if (root == NULL) return NULL;
  616. while (! feof(fp)) {
  617. /* Read a triple and check for consistency. */
  618. err = fscanf(fp, "%d %d %s", &low, &size, attrib);
  619. if (err == EOF) {
  620. break;
  621. } else if (err != 3) {
  622. Mtr_FreeTree(root);
  623. return(NULL);
  624. } else if (low < 0 || low+size > nleaves || size < 1) {
  625. Mtr_FreeTree(root);
  626. return(NULL);
  627. } else if (strlen(attrib) > 8 * sizeof(MtrHalfWord)) {
  628. /* Not enough bits in the flags word to store these many
  629. ** attributes. */
  630. Mtr_FreeTree(root);
  631. return(NULL);
  632. }
  633. /* Parse the flag string. Currently all flags are permitted,
  634. ** to make debugging easier. Normally, specifying NEWNODE
  635. ** wouldn't be allowed. */
  636. flags = MTR_DEFAULT;
  637. for (c=attrib; *c != 0; c++) {
  638. switch (*c) {
  639. case 'D':
  640. break;
  641. case 'F':
  642. flags |= MTR_FIXED;
  643. break;
  644. case 'N':
  645. flags |= MTR_NEWNODE;
  646. break;
  647. case 'S':
  648. flags |= MTR_SOFT;
  649. break;
  650. case 'T':
  651. flags |= MTR_TERMINAL;
  652. break;
  653. default:
  654. return NULL;
  655. }
  656. }
  657. node = Mtr_MakeGroup(root, (MtrHalfWord) low, (MtrHalfWord) size,
  658. flags);
  659. if (node == NULL) {
  660. Mtr_FreeTree(root);
  661. return(NULL);
  662. }
  663. }
  664. return(root);
  665. } /* end of Mtr_ReadGroups */
  666. /*---------------------------------------------------------------------------*/
  667. /* Definition of internal functions */
  668. /*---------------------------------------------------------------------------*/
  669. /*---------------------------------------------------------------------------*/
  670. /* Definition of static functions */
  671. /*---------------------------------------------------------------------------*/
  672. /**
  673. @brief Adjusts the low fields of a node and its descendants.
  674. @details Adds shift to low of each node. Checks that no
  675. out-of-bounds values result.
  676. @return 1 in case of success; 0 otherwise.
  677. @sideeffect None
  678. */
  679. static int
  680. mtrShiftHL(
  681. MtrNode * node /**< group tree node */,
  682. int shift /**< amount by which low should be changed */)
  683. {
  684. MtrNode *auxnode;
  685. int low;
  686. low = (int) node->low;
  687. low += shift;
  688. if (low < 0 || low + (int) (node->size - 1) > (int) MTR_MAXHIGH) return(0);
  689. node->low = (MtrHalfWord) low;
  690. if (!MTR_TEST(node,MTR_TERMINAL) && node->child != NULL) {
  691. auxnode = node->child;
  692. do {
  693. if (!mtrShiftHL(auxnode,shift)) return(0);
  694. auxnode = auxnode->younger;
  695. } while (auxnode != NULL);
  696. }
  697. return(1);
  698. } /* end of mtrShiftHL */