/usr/include/cdlcore.hxx is in ecosconfig-imx 200910-0ubuntu4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 | #ifndef __CDLCORE_HXX
# define __CDLCORE_HXX
//{{{ Banner
//==========================================================================
//
// cdlcore.hxx
//
// The core parts of the library. This header defines aspects of
// CDL that are shared between software cdl, hcdl, scdl, and any
// future languages based on the same core technology.
//
//==========================================================================
//####COPYRIGHTBEGIN####
//
// ----------------------------------------------------------------------------
// Copyright (C) 2002 Bart Veer
// Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
//
// This file is part of the eCos host tools.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// ----------------------------------------------------------------------------
//
//####COPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): bartv
// Contributors: bartv
// Date: 1999-04-15
//
//####DESCRIPTIONEND####
//==========================================================================
//}}}
//{{{ Platform dependencies
// ----------------------------------------------------------------------------
// Visual C++ has the delightful feature that the source browser will generate
// warnings if there are any identifiers of length >= 256 characters, while at
// the same time use of templates in the standard C++ library can easily
// generate functions that long. It appears that the only way to disable the
// warnings is by use of a %$#@(%*&%! #pragma.
//
// Similarly, VC++ gives spurious warnings when it comes to multiple virtual
// inheritance.
#ifdef _MSC_VER
# pragma warning( disable: 4786 )
# pragma warning( disable: 4250 )
#endif
//}}}
//{{{ nested #include's
// ----------------------------------------------------------------------------
// The libcdl API is defined using parts of the standard C++ library,
// including strings and various bits of STL. Therefore these headers must
// be #include'd here for the header file to work.
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <string>
#include <functional>
#include <algorithm>
// <cstring> is needed because newer GCC's require the header
// to be included to have access to strcpy() and friends
#include <cstring>
// <cctype> is needed in various places in the implementation.
// This #include should be moved to an implementation-specific
// header.
#include <cctype>
// Now for some eCos host-side infrastructure headers.
//
// Get the cyg_int64 data type and CYG_UNUSED_PARAM() macro.
#include <cyg/infra/cyg_type.h>
// Some of the classes need to reference the cyg_assert_class_zeal enum.
// Also inline functions may perform assertions.
#include <cyg/infra/cyg_ass.h>
// This header file also depends on having a suitable Tcl installation
// Unfortunately <tcl.h> does some ugly things in the interests of
// portability, including defining symbols such as EXTERN when
// necessary, and this has to be patched up here as cleanly as possible.
#ifndef CONST
# define __CDL_CONST_UNDEFINED
#endif
#ifndef EXTERN
# define __CDL_EXTERN_UNDEFINED
#endif
#ifndef VOID
# define __CDL_VOID_UNDEFINED
#endif
#ifndef CHAR
# define __CDL_CHAR_UNDEFINED
#endif
#ifndef SHORT
# define __CDL_SHORT_UNDEFINED
#endif
#ifndef LONG
# define __CDL_LONG_UNDEFINED
#endif
extern "C" {
#include <tcl.h>
}
#ifdef __CDL_CONST_UNDEFINED
# undef CONST
# undef __CDL_CONST_UNDEFINED
#endif
#ifdef __CDL_EXTERN_UNDEFINED
# undef EXTERN
# undef __CDL_EXTERN_UNDEFINED
#endif
#ifdef __CDL_VOID_UNDEFINED
# undef VOID
# undef __CDL_VOID_UNDEFINED
#endif
#ifdef __CDL_CHAR_UNDEFINED
# undef CHAR
# undef __CDL_CHAR_UNDEFINED
#endif
#ifdef __CDL_SHORT_UNDEFINED
# undef SHORT
# undef __CDL_SHORT_UNDEFINED
#endif
#ifdef __CDL_LONG_UNDEFINED
# undef LONG
# undef __CDL_LONG_UNDEFINED
#endif
//}}}
//{{{ Primitive types, constants:, enums, etc.
// ----------------------------------------------------------------------------
// The CDL languages are defined in terms of arbitrary precision
// arithmetic. This is necessary to allow e.g. pointers to be
// manipulated at the CDL level on 64 bit target processors.
//
// Temporarily it is not necessary to provide this precision, so it is
// convenient to stick to 64 bit integers as provided by the
// underlying infrastructure. However the API is defined in terms of
// the type cdl_int, so that it will be easier in future to make the
// change to the correct datatype. At that point cdl_int can be
// redefined to be a class which supports the appropriate operators.
typedef cyg_int64 cdl_int;
// ---------------------------------------------------------------------------
// A common concept in the CDL language is a small amount of TCL code.
// This is currently stored as a simple string. Conceivably it could
// be byte-compiled and stored accordingly.
typedef std::string cdl_tcl_code;
// ----------------------------------------------------------------------------
// CDL values.
//
// CDL is a declarative programming language. It does involve the
// manipulation of values, but such values do not necessarily
// correspond to hardware-level entities such as integers or double
// precision numbers. Hence the term "type" is avoided, "flavor"
// is used instead. CDL understands four different flavors.
//
// None | Bool
// --------+--------
// Data |BoolData
//
//
// The flavor "none" is used for entities that serve only as
// placeholders in the hierarchy, allowing other entities to be
// grouped more easily.
//
// Boolean entities can be either enabled or disabled. This is the
// most common flavor for software configuration options, the user can
// either enable or disable some unit of functionality. For software
// packages implemented in C or C++ the implementation is obvious: iff
// the entity is enabled then there will be a #define, and code will
// check the setting using e.g. #ifdef.
//
// The flavor "data" implies some arbitrary data. Internally this will
// be held as a string. Other properties such as legal_values,
// check_proc and entry_proc can be used to constrain the
// actual values, for example to an integer value within a certain
// range.
//
// The flavor "booldata" combines the previous two: it means that
// the option can be either enabled or disabled, and if it is
// enabled then it must have a value as per legal_values etc.
// One example of this is a software package: this may be either
// enabled or disabled, and if it is enabled then it has a value
// corresponding to the version string. Another example is a hardware
// pin: this may or may not be connected, and if it is connected
// then its value identifies some other pin.
//
// An entity's flavor is not always sufficient by itself to specify
// how the user can manipulate it in a graphical tool. Obviously an
// entity of flavor "none" cannot be manipulated at all. Flavor "bool"
// normally implies a checkbutton, but occasionally a radiobutton will
// be more appropriate. "Data" says very little about the user
// interaction, it will be necessary to examine other properties such
// as legal_values to determine a sensible representation. The same
// goes for "BoolData", with the additional possibility that the
// entity may be disabled.
//
// It can be argued that three of the flavors are redundant: both Bool
// and BoolData could be implemented as cases of "Data" with a special
// legal value "disabled" (or false, or whatever); "None" could be
// implemented as constant "Data"; effectively CDL would manipulate
// all data as strings, just like e.g. all variables in Tcl, or just
// like all scalars in Perl. This approach is certainly tempting and
// might well make it easier to document the language, but in practice
// it would result in more verbose CDL: boolean entities really are a
// different beast from data entities.
//
// It can also be argued that there should be more flavors. For
// example there could be separate flavors for integer data, floating
// point data, string data, and so on. There are a number of good
// reasons for not doing so:
//
// 1) applying separate constraints such as legal_values allows much
// finer control over the actual values, for example numbers within a
// given range. As likely as not, a value will be constrained to
// something smaller than the range MININT to MAXINT (whatever those
// happen to be for the current target).
//
// 2) where do you stop? Do you provide separate flavors for signed
// vs. unsigned? Char, wchar_t, short, int, long, long long? How about
// the eCos data types cyg_ucount8, cyg_uint8, ... Is there support
// for enums? Arrays? Bitfields? Structures? Unions? C++ classes?
// How about other programming languages such as Ada or Java?
//
// Any attempt to implement a grand union of all data types in CDL
// is doomed to failure and should not be attempted. Treating
// everything as a string instead has proven successful in a number
// of languages, including Tcl and Perl.
//
// 3) for some variants of CDL, for example hardware CDL, it may not
// make much sense to display a value directly and allow it to be
// manipulated directly. The value associated with a pin entity
// identifies the pin to which it is connected, and typically
// this value will be manipulated by drag and drop rather than by
// typing some characters. Such a value certainly does not correspond
// to any machine data type.
//
// Another reason for extending the number of flavors is to provide
// more information. For example there could be a specialized version
// of the boolean flavor called "radio". This would imply a specific
// representation in the user interface, and it would also impose
// a constraint that it implicitly precludes any other radio entities
// within the same group. However the same information can be specified
// by other more general means such as requires statements.
enum CdlValueFlavor {
CdlValueFlavor_Invalid = 0,
CdlValueFlavor_None = 1,
CdlValueFlavor_Bool = 2,
CdlValueFlavor_BoolData = 3,
CdlValueFlavor_Data = 4
};
// Another important aspect of a value is where it came from. There
// are a number of possible sources: the default value, calculated
// from a default_value property; a value inferred by the inference
// engine; a value set by a wizard; and a value set explicitly by
// the user. These sources have different priorities, so for example
// the inference engine can safely replace a calculated default
// value without prompting the user, but changing a user-set value
// automatically is undesirable.
//
// Wizard-generated values are considered more valuable than default
// or inferred values (there is some user input involved), but less
// valuable than values set explicitly by the user: the idea is that
// a wizard asks fairly generic questions and makes a best guess at
// the correct values, which may not be precise enough for the
// user's needs.
//
// Arguably dialogs provide a level between wizards and users, in that
// a dialog can theoretically manipulate several entities in one go so
// it is a less precise way of setting values. At this stage it does
// not seem worthwhile to add this distinction.
//
// The library actually maintains separate values for each source,
// as well as the current source which is what actually gets used.
// In theory it is possible for the user interface code to let
// the user switch between these. It is not yet clear whether this
// makes sense from an end user's perspective.
enum CdlValueSource {
CdlValueSource_Invalid = -1, // 0 is needed for array indexing
CdlValueSource_Default = 0,
CdlValueSource_Inferred = 1,
CdlValueSource_Wizard = 2,
CdlValueSource_User = 3,
CdlValueSource_Current = 4
};
// ----------------------------------------------------------------------------
// Update support.
//
// When there is a change to a node and there are references to that node,
// the referencing properties will want to be informed about this. There
// are various different kinds of changes, not all of which are always
// relevant. For example, if a CDL entity gets destroyed or unloaded then
// all referencing entities are likely to want to know about this, but
// if a container's value changes then this has no effect on a reference
// in e.g. a "parent" property. In some cases it is also useful to apply
// updates to nodes rather than properties, e.g. when a node becomes
// active or inactive.
//
// The generic update code is also used for initialization and finalization,
// i.e. when the source object itself has just been loaded or is
// being unloaded.
//
// For any particular update at most one bit set, but it is often
// appropriate to treat several different kinds of update with
// common code. Hence the enum values can be or'ed and and'ed.
enum CdlUpdate {
CdlUpdate_Loaded = 0x0001, // The source has just been loaded
CdlUpdate_Init = 0x0002, // Second-phase of a load operation
CdlUpdate_Unloading = 0x0004, // The source is being unloaded
CdlUpdate_Created = 0x0008, // The destination has just been created
CdlUpdate_Destroyed = 0x0010, // The destination is being destroyed
CdlUpdate_ValueChange = 0x0020, // The destination's value has changed.
// This gets applied to nodes as well
CdlUpdate_ActiveChange = 0x0040 // The node has become active or inactive
};
// ----------------------------------------------------------------------------
// Inference engine callback.
//
// During a transaction there may be one or more invocations of the inference
// engine, followed by a callback which should display the current transaction
// status to the user and allow one or more recommended fixes to be accepted.
// The callback's return code indicates what should happen next. "Cancel"
// is pretty obvious. "Continue" may result in a commit, or it may result in
// another iteration.
enum CdlInferenceCallbackResult {
CdlInferenceCallbackResult_Continue = 0x01,
CdlInferenceCallbackResult_Cancel = 0x02
};
// ----------------------------------------------------------------------------
// Widget hints.
//
// The library can provide a hint to the GUI code as to a sensible
// widget to use for displaying a particular valuable. There are separate
// hints for the bool and data parts.
enum CdlBoolWidget {
CdlBoolWidget_None = 0, // The boolean part is not applicable
CdlBoolWidget_CustomDialog = 1, // There is a valid custom dialog property
CdlBoolWidget_CheckButton = 2, // For simple booleans
CdlBoolWidget_Radio = 3, // For several mutual exclusive options,
// the data structure will provide a string identifier
};
enum CdlValueWidget {
CdlValueWidget_None = 0, // The value part is not applicable
CdlValueWidget_CustomDialog = 1, // There is a valid custom dialog property
CdlValueWidget_Loadable = 2, // Use package/version dialog
CdlValueWidget_EntryBox = 3, // Fallback
CdlValueWidget_MultilineString = 4, // For complicated strings
CdlValueWidget_DecimalRange = 5, // e.g. 1 to 16
// Could be implemented as scale, radio buttons, entry, pull-down menu,
// combo box, ... depending on GUI conventions and number of entries
CdlValueWidget_HexRange = 6, // e.g. 0x01 to 0x10
CdlValueWidget_OctalRange = 7, // e.g. 01 to 020
CdlValueWidget_DoubleRange = 8, // e.g. 0.1 to 0.2
CdlValueWidget_NumericSet = 9, // e.g. 1 2 4 8 16
// The exact nature of the numbers is irrelevant, they will only
// get displayed, not edited
// Could be implemented as radio buttons, entry widget, pull-down menu,
// combo box, ... depending on GUI conventions and number of entries
// Each entry can have its own representation
CdlValueWidget_StringSet = 10 // e.g. "ram", "rom"
// More to be added, e.g. for compiler flag handling
};
// ----------------------------------------------------------------------------
// Value formats.
//
// The CDL input data can accept numbers in a variety of formats,
// for example hexadecimal as well as decimal. It is desirable to try
// to keep track of this formatting information where possible, so
// that what the user sees and what ends up in header files corresponds
// more closely to what is in the raw CDL data. For example, it is
// much easier to understand 0x7fffffff than its decimal equivalent.
//
// The information kept here is very imprecise, it provides only
// minimal formatting information. It is not clear yet whether this
// will suffice or whether something more exact is going to be needed.
enum CdlValueFormat
{
CdlValueFormat_Default = 0,
CdlValueFormat_Hex = 1,
CdlValueFormat_Octal = 2
};
//}}}
//{{{ Exception classes
// ----------------------------------------------------------------------------
// Some parts of the library make use of C++ exception handling. A number
// of exception classes related to this library are useful. In addition
// just about every part of the library can throw std::bad_alloc, but this
// is not checked for explicitly anywhere.
// This class is used for all exceptions where an error message should
// be displayed to the user. There is a single string message associated
// with the exception.
class CdlStringException {
friend class CdlTest;
public:
CdlStringException(std::string message_arg) {
message = message_arg;
}
CdlStringException(const CdlStringException& original) {
message = original.message;
}
CdlStringException& operator=(const CdlStringException& original) {
message = original.message;
return *this;
}
~CdlStringException() {
message = "";
}
const std::string& get_message() const {
return message;
}
private:
std::string message;
CdlStringException();
};
// CdlInputOutputException: this gets thrown when something goes wrong during
// file I/O operations, e.g. a file exists but cannot be opened. The
// exception contains a simple string explaining the error. This string
// may contain multiple lines, it is intended to be written to stderr
// or displayed in either a text widget or a dialog box.
//
// A separate class rather than a typedef is used to avoid any possible
// error message confusion. Everything gets inlined so there should be
// no performance issues.
class CdlInputOutputException : public CdlStringException {
friend class CdlTest;
public:
CdlInputOutputException(std::string message_arg) :
CdlStringException(message_arg) {
}
CdlInputOutputException(const CdlInputOutputException& original) :
CdlStringException(original) {
}
CdlInputOutputException& operator=(const CdlInputOutputException& original) {
(void) CdlStringException::operator=(original);
return *this;
}
};
// This class is used when any parsing happens at the C++ level rather
// than at the Tcl level. The exception should be caught before it
// propagates through the Tcl interpreter, or the latter will end up
// in an inconsistent state.
class CdlParseException : public CdlStringException {
friend class CdlTest;
public:
CdlParseException(std::string message_arg) :
CdlStringException(message_arg) {
}
CdlParseException(const CdlParseException& original) :
CdlStringException(original) {
}
CdlParseException& operator=(const CdlParseException& original) {
(void) CdlStringException::operator=(original);
return *this;
}
};
// Evaluating an expression may fail for a variety of reasons, e.g. because
// some referenced entity has not been loaded into the configuration.
// This exception can be thrown in such cases.
class CdlEvalException : public CdlStringException {
friend class CdlTest;
public:
CdlEvalException(std::string message_arg) :
CdlStringException(message_arg) {
}
CdlEvalException(const CdlEvalException& original) :
CdlStringException(original) {
}
CdlEvalException& operator=(const CdlEvalException& original) {
(void) CdlStringException::operator=(original);
return *this;
}
};
//}}}
//{{{ Forward declarations of the body classes
// ----------------------------------------------------------------------------
// This section provides forward declarations of the main classes in
// the core of the library. Each variant of CDL will define additional
// classes, e.g. cdl_option, but these will usually be derived from
// the core ones.
// There are three types of expression in CDL:
// 1) ordinary expressions evaluate to a single value. The most common
// use is for the legal_values property.
// 2) list expressions evaluate to a range of values, e.g. 1 to 10,
// and the most common use is for the legal_values property.
// 3) goal expressions evaluate to either true or false and are used
// for e.g. requires and active_if properties.
class CdlExpressionBody;
class CdlListExpressionBody;
class CdlGoalExpressionBody;
// There are also objects for simple values, values and list values.
// These are expanded classes, there are no associated pointer
// types. It is quite likely that values need to be copied around
// on the stack.
class CdlSimpleValue;
class CdlValue;
class CdlListValue;
// Properties. The base class is CdlProperty, and there are a number
// of derived classes provided as standard. Additional derived classes
// may be added in future.
class CdlPropertyBody;
class CdlProperty_MinimalBody;
class CdlProperty_StringBody;
class CdlProperty_TclCodeBody;
class CdlProperty_ReferenceBody;
class CdlProperty_StringVectorBody;
class CdlProperty_ExpressionBody;
class CdlProperty_ListExpressionBody;
class CdlProperty_GoalExpressionBody;
// Base classes. CDL entities such as options and components derive
// from one or more of these, using virtual inheritance.
//
// The lowest-level class is CdlNodeBody.
//
// 1) a node usually lives in a hierarchy, below a toplevel
// and with a container object as the parent. However nodes
// can live outside a container on a temporary basis,
// and toplevel objects have no parent.
//
// 2) a node has a name that is unique within the hierarchy.
//
// 3) a node has a vector of properties. Actually some entities
// will have an empty vector, e.g. the orphans container
// that is internal to the library. However it is too
// inconvenient to have separate base classes for these.
//
// 4) nodes can be referred to by properties in other nodes.
class CdlNodeBody;
// A container is a node that can contain other nodes.
class CdlContainerBody;
// A loadable object is a container whose data has come out of a CDL
// script of some sort. It also stores details about all entities that
// were loaded via this script (even if some of them were reparented)
// thus supporting unload operations.
class CdlLoadableBody;
// A toplevel object is a container that acts as the toplevel of
// a hierarchy, in other words its parent is always 0. In addition
// a toplevel keeps track of all the names used in the hierarchy,
// thus facilitating navigation.
class CdlToplevelBody;
// The remaining classes all add functionality to CdlNode, directly or
// indirectly.
//
// A user-visible object is likely to appear in the user interface.
// This means it may have an alias string, a description, a
// documentation URL, and a gui_hint field.
class CdlUserVisibleBody;
// A valuable object has a value that can be retrieved but not
// necessarily modified by the user. For example the value of an
// interface is always calculated and users can never change it.
// Valuable objects have a whole bunch of associated properties
// including dependencies.
class CdlValuableBody;
// A parentable object has the parent property, i.e. it can
// be reparented to anywhere in the hierarchy
class CdlParentableBody;
// A buildable object is a valuable object that may result in
// something being built, typically a library in the case of
// software packages.
class CdlBuildableBody;
// A loadable that contains buildables
class CdlBuildLoadableBody;
// A definable object is a valuable object whose value can result
// in #define statements in a header file
class CdlDefinableBody;
// A loadable which can contain definables
class CdlDefineLoadableBody;
// TODO: add instantiation support
// Custom dialogs and wizards are provided by the core.
class CdlDialogBody;
class CdlWizardBody;
class CdlInterfaceBody;
// Support for Tcl interpreters is also in the core, since it is
// difficult to do anything CDL-related without at least one Tcl
// interpreter lying around.
class CdlInterpreterBody;
// The basic conflict class is part of the core library, as are a
// number of common derived classes for specific types of conflict.
class CdlConflictBody;
class CdlConflict_UnresolvedBody;
class CdlConflict_IllegalValueBody;
class CdlConflict_EvalExceptionBody;
class CdlConflict_RequiresBody;
class CdlConflict_DataBody;
// Many operations happen (or may happen) in the context of a
// transaction. This is necessary to keep track of the various
// changes that can happen: for example, changing a component's
// value may require other entities' default values to be
// recalculated; it may change some legal_values list expressions,
// causing current values to become invalid; it may affect
// "requires" properties, causing goals to become satisfied or
// not-satisfied; it may change the "active" state of everything
// below the component, not to mention any entity with an
// "active_if" properties, and when an entity becomes active or
// inactive that may in turn affect other entities.
//
// Keeping track of all of this via recursion is possible, but there
// are problems. If an entity is updated multiple times, no
// optimizations are possible. It becomes much more difficult to
// detect cycles. During an unload operation things can get very
// messy. There is no easy way to track all of the changes and report
// them to higher level code via a callback. There is no support
// for any kind of rollback. A transaction model potentially
// provides support for all of this, at the cost of a more
// complex API.
class CdlTransactionBody;
// This class is used to pass information back to the application
// about what has actually changed in a transaction.
class CdlTransactionCallback;
// Build info class. This is always an expanded object, but is
// needed here to break a circular dependency.
class CdlBuildInfo;
// ----------------------------------------------------------------------------
// Typedefs for the pointers. There are separate typedefs to cope with
// const vs. non-const objects. Otherwise you end up with the problem
// that "const CdlNode x" means that the pointer is const, not the
// object pointed at.
typedef CdlExpressionBody* CdlExpression;
typedef CdlListExpressionBody* CdlListExpression;
typedef CdlGoalExpressionBody* CdlGoalExpression;
typedef CdlPropertyBody* CdlProperty;
typedef CdlProperty_MinimalBody* CdlProperty_Minimal;
typedef CdlProperty_StringBody* CdlProperty_String;
typedef CdlProperty_TclCodeBody* CdlProperty_TclCode;
typedef CdlProperty_ReferenceBody* CdlProperty_Reference;
typedef CdlProperty_StringVectorBody* CdlProperty_StringVector;
typedef CdlProperty_ExpressionBody* CdlProperty_Expression;
typedef CdlProperty_ListExpressionBody* CdlProperty_ListExpression;
typedef CdlProperty_GoalExpressionBody* CdlProperty_GoalExpression;
typedef CdlNodeBody* CdlNode;
typedef CdlContainerBody* CdlContainer;
typedef CdlLoadableBody* CdlLoadable;
typedef CdlToplevelBody* CdlToplevel;
typedef CdlUserVisibleBody* CdlUserVisible;
typedef CdlValuableBody* CdlValuable;
typedef CdlParentableBody* CdlParentable;
typedef CdlBuildableBody* CdlBuildable;
typedef CdlBuildLoadableBody* CdlBuildLoadable;
typedef CdlDefinableBody* CdlDefinable;
typedef CdlDefineLoadableBody* CdlDefineLoadable;
typedef CdlDialogBody* CdlDialog;
typedef CdlWizardBody* CdlWizard;
typedef CdlInterfaceBody* CdlInterface;
typedef CdlInterpreterBody* CdlInterpreter;
typedef CdlConflictBody* CdlConflict;
typedef CdlConflict_UnresolvedBody* CdlConflict_Unresolved;
typedef CdlConflict_IllegalValueBody* CdlConflict_IllegalValue;
typedef CdlConflict_EvalExceptionBody* CdlConflict_EvalException;
typedef CdlConflict_RequiresBody* CdlConflict_Requires;
typedef CdlConflict_DataBody* CdlConflict_Data;
typedef CdlTransactionBody* CdlTransaction;
// ----------------------------------------------------------------------------
typedef const CdlExpressionBody* CdlConstExpression;
typedef const CdlListExpressionBody* CdlConstListExpression;
typedef const CdlGoalExpressionBody* CdlConstGoalExpression;
typedef const CdlPropertyBody* CdlConstProperty;
typedef const CdlProperty_MinimalBody* CdlConstProperty_Minimal;
typedef const CdlProperty_StringBody* CdlConstProperty_String;
typedef const CdlProperty_TclCodeBody* CdlConstProperty_TclCode;
typedef const CdlProperty_ReferenceBody* CdlConstProperty_Reference;
typedef const CdlProperty_StringVectorBody* CdlConstProperty_StringVector;
typedef const CdlProperty_ExpressionBody* CdlConstProperty_Expression;
typedef const CdlProperty_ListExpressionBody* CdlConstProperty_ListExpression;
typedef const CdlProperty_GoalExpressionBody* CdlConstProperty_GoalExpression;
typedef const CdlNodeBody* CdlConstNode;
typedef const CdlContainerBody* CdlConstContainer;
typedef const CdlLoadableBody* CdlConstLoadable;
typedef const CdlToplevelBody* CdlConstToplevel;
typedef const CdlUserVisibleBody* CdlConstUserVisible;
typedef const CdlValuableBody* CdlConstValuable;
typedef const CdlParentableBody* CdlConstParentable;
typedef const CdlBuildableBody* CdlConstBuildable;
typedef const CdlBuildLoadableBody* CdlConstBuildLoadable;
typedef const CdlDefinableBody* CdlConstDefinable;
typedef const CdlDefineLoadableBody* CdlConstDefineLoadable;
typedef const CdlDialogBody* CdlConstDialog;
typedef const CdlWizardBody* CdlConstWizard;
typedef const CdlInterfaceBody* CdlConstInterface;
typedef const CdlInterpreterBody* CdlConstInterpreter;
typedef const CdlConflictBody* CdlConstConflict;
typedef const CdlConflict_UnresolvedBody* CdlConstConflict_Unresolved;
typedef const CdlConflict_IllegalValueBody* CdlConstConflict_IllegalValue;
typedef const CdlConflict_EvalExceptionBody* CdlConstConflict_EvalException;
typedef const CdlConflict_RequiresBody* CdlConstConflict_Requires;
typedef const CdlConflict_DataBody* CdlConstConflict_Data;
typedef const CdlTransactionBody* CdlConstTransaction;
//}}}
//{{{ Miscellaneous types etc.
// ----------------------------------------------------------------------------
// This section is used for data types, function prototypes, etc. which could
// not be defined until after the main CDL classes and handles.
// This typedef is used for error and warning reporting functions.
// Typically such a function pointer will be passed when the library
// is asked to perform any non-trivial parsing operation, e.g. loading
// a package.
//
// If the error is fatal then this callback function should raise
// a CdlParseException.
typedef void (*CdlDiagnosticFnPtr)(std::string);
// ----------------------------------------------------------------------------
// This function is used for update handler. Whenever there is a change
// to CDL entity (it has just been loaded, or its value has changed, or
// whatever) this can affect other CDL entities that reference it.
// All such references occur via properties, and there should be
// update handlers associated with those properties.
//
// Update handlers are also invoked for initialization and finalization
// operations, i.e. when the source object itself has just been loaded
// or is in the process of being unloaded.
//
// The arguments to an update handler are:
// 1) the transaction in which the operation takes place
// 2) the source object containing the reference
// 3) the source property containing the reference
// 4) the destination object. This may be 0 for some update
// operations.
// 5) an indication of the change that has happened. This should
// be a CdlUpdate value.
typedef void (*CdlUpdateHandler)(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
// ----------------------------------------------------------------------------
// This function is also used for transactions. Typically during a
// transaction there will be one or more invocations of the inference engine,
// with callbacks in between to allow one or more of the recommended
// changes to be undone.
typedef CdlInferenceCallbackResult (*CdlInferenceCallback)(CdlTransaction);
// ----------------------------------------------------------------------------
// The TCL API and C++ do not always mesh cleanly, for example a lot
// happens in terms of ClientData which is a void* pointer. To avoid
// too many casts all over the place libcdl provides a CdlInterpreter
// class and the following alternative to Tcl_CmdProc*. A single
// function will be used for the TCL command: its ClientData will be
// the CdlInterpreterCommand, and the CdlInterpreter is accessible via
// AssocData. This does result in some overheads, but none of these
// should be in performance-critical code.
typedef int (*CdlInterpreterCommand)(CdlInterpreter, int, const char*[]);
// ----------------------------------------------------------------------------
// In the libcdl world it is often convenient to swap whole sets of
// commands in and out. For example when executing the body of a
// cdl_component it is desirable to swap in commands for all the
// properties that make sense in a component and swap out all the
// commands that made sense in a higher level. It is assumed that none
// of the commands being swapped in or out are built-ins. Achieving
// this involves a vector of this simple utility structure.
class CdlInterpreterCommandEntry {
public:
std::string name;
CdlInterpreterCommand command;
CdlInterpreterCommandEntry() : name(""), command(0) {}
CdlInterpreterCommandEntry(const char *name_arg, CdlInterpreterCommand command_arg)
: name(name_arg), command(command_arg)
{
}
CdlInterpreterCommandEntry(std::string name_arg, CdlInterpreterCommand command_arg)
: name(name_arg), command(command_arg)
{
}
~CdlInterpreterCommandEntry()
{
name = "";
command = 0;
}
};
// ----------------------------------------------------------------------------
// Persistence support.
// Some applications want to be able to store additional information
// in savefiles, and essentially this involves extra commands that
// get executed when the savefile is executed. It is possible that
// the application reading back the savefile does not understand
// the same set of commands as the application that wrote back the
// data, so the library tries hard not to lose data.
//
// The CdlSaveCallback function typedef is used when installing
// an application-specific savefile command. The first argument
// indicates the node for which the callback is being invoked:
// this may be the entire toplevel, or just an option, or whatever.
//
// The CdlSavefileCommand structure keeps track of the command,
// the save callback if any (non-zero only for application-specific
// data, zero implies that the command is handled by the lirary).
// The load command is invoked when reading in a savefile and the
// appropriate command is executed: unrecognised commands will be
// processed by CdlToplevelBody::savefile_handle_unknown().
typedef void (*CdlSaveCallback)(CdlNode, CdlInterpreter, Tcl_Channel, int);
struct CdlSavefileCommand {
std::string name;
CdlSaveCallback save_callback;
CdlInterpreterCommand load_command;
};
// ----------------------------------------------------------------------------
// Widget hint.
// This structure provides widget hint information for a CdlValuable.
// There are separate hints for the bool and data parts, and possibly
// some additional data such as a string identifying the set of
// items in a radio button.
struct CdlWidgetHint {
CdlBoolWidget bool_widget;
CdlValueWidget value_widget;
std::string radio_button_interface;
};
//}}}
//{{{ Memory leak detection
// ----------------------------------------------------------------------------
// Provide some macros that are useful for detecting memory leaks. Basically
// there is a static counter for every class, which gets incremented by the
// constructor(s) and decremented by the destructor. Memory leak detection
// is currently enabled if tracing is enabled. It would be possible to use
// another configure-time option, but the overheads of tracing are likely
// to dwarf the overheads of memory leak detection.
//
// For now the memleak counters are always present, even in non-debug
// versions. The overhead is sufficiently small that it can be
// ignored.There is control over whether or not the counters get
// updated in the constructor or destructor. Otherwise there would be problems
// with whether or not there should be a semicolon at the end of the
// CYGDBG_DECLARE_MEMLEAK_COUNTER() macro definition.
#define CYGDBG_DECLARE_MEMLEAK_COUNTER() static int memleak_counter
#define CYGDBG_DEFINE_MEMLEAK_COUNTER(class) int class::memleak_counter = 0
#define CYGDBG_GET_MEMLEAK_COUNTER(class) class::memleak_counter
#ifdef CYGDBG_USE_TRACING
#define CYGDBG_MEMLEAK_CONSTRUCTOR() this->memleak_counter++;
#define CYGDBG_MEMLEAK_DESTRUCTOR() this->memleak_counter--;
#define CYGDBG_MEMLEAK_CHECKTHIS() if (this->memleak_counter < 0) { return false; }
#else
#define CYGDBG_MEMLEAK_CONSTRUCTOR()
#define CYGDBG_MEMLEAK_DESTRUCTOR()
#define CYGDBG_MEMLEAK_CHECKTHIS()
#endif
//}}}
//{{{ Cdl class
// ---------------------------------------------------------------------------
// The sole purpose of this class is to provide some utility functions with
// reasonable namespace protection, without requiring that the compiler
// implements namespaces.
class Cdl {
public:
static bool is_valid_value_flavor(CdlValueFlavor);
static bool is_valid_value_source(CdlValueSource);
static bool is_valid_cdl_name(const std::string&);
static bool is_valid_c_preprocessor_symbol(const std::string&);
static bool string_to_integer(std::string, cdl_int&);
static bool string_to_double(std::string, double&);
static bool string_to_bool(std::string, bool&);
static void integer_to_string(cdl_int, std::string&, CdlValueFormat = CdlValueFormat_Default);
static std::string integer_to_string(cdl_int, CdlValueFormat = CdlValueFormat_Default);
static void double_to_string(double, std::string&, CdlValueFormat = CdlValueFormat_Default);
static std::string double_to_string(double, CdlValueFormat = CdlValueFormat_Default);
static void bool_to_string(bool, std::string&);
static std::string bool_to_string(bool);
static void integer_to_double(cdl_int, double&);
static double integer_to_double(cdl_int);
static bool double_to_integer(double, cdl_int&);
static bool string_to_flavor(std::string, CdlValueFlavor&);
static bool flavor_to_string(CdlValueFlavor, std::string&);
static bool string_to_source(std::string, CdlValueSource&);
static bool source_to_string(CdlValueSource, std::string&);
static std::string get_library_version();
static void set_interactive(bool = true);
static bool is_interactive();
static bool truth() { return true; }
static bool falsehood() { return false; }
// return values are -1,0,1 just like strcmp(). The most recent
// version is the smallest.
static int compare_versions(std::string, std::string);
// Also provide an STL-friendly comparison class
class version_cmp {
public:
bool operator()(const std::string& v1, const std::string& v2) const {
return Cdl::compare_versions(v1,v2) < 0;
}
};
// Split a version string into major, minor and release numbers.
static void split_version_string(const std::string&, std::string& /* major */,
std::string& /* minor */, std::string& /* release */);
// It is occasionally useful to take a full CDL name such as CYGPKG_KERNEL
// and turn it into a short form, i.e. kernel.
static std::string get_short_form(const std::string&);
private:
static bool interactive;
};
//}}}
//{{{ CdlInterpreter class
// ----------------------------------------------------------------------------
// libcdl requires access to a Tcl interpreter. For now the standard
// interpreter is used. In the long run it may be better to use a
// custom parser in places, if only to improve the diagnostics messages
// that users see.
//
// Consider the case of software CDL (other CDL variants will have
// similar requirements). A Tcl interpreter is needed to read in the
// data for a given package. It will also be needed at various stages
// when the data is being manipulated, e.g. to display a custom dialog
// or to execute e.g. a check_proc or a define_proc. Each package
// should run in its own safe interpreter with limited capabilities:
// file I/O is limited to read-only, but read-write in the build and
// install trees; network I/O is out of the question, at least until
// appropriate security support is added to the CDL language itself.
// However the interpreter should be extended with additional commands
// like cdl_get and cdl_set to access the configuration data.
//
// For security and robustness reasons it is desirable to have
// separate interpreters for the various packages. This leads to the
// concept of a master interpreter for the entire configuration, and a
// group of slave interpreters, one per package. In this model it
// is convenient to have the configuration and package entities
// associated directly with the interpreter. Note that a single
// application may have several configurations loaded in memory,
// so there may be several master interpreters.
//
// Some applications will want to support the graphical side of CDL,
// i.e. custom dialogs and wizards. This means linking in Tk, not to
// mention X11 (or the Windows equivalents), and making some/all of
// the Tk commands available to the safe interpreter. Arguably
// commands like toplevel should always be disabled. Not all clients
// of libcdl will want the overheads of linking with Tk and X, so this
// has to be made optional.
//
// The approach taken is as follows:
//
// 1) there is a class CdlInterpreter which provides access to Tcl
// interpreters. Amongst other things it takes care of converting
// between C and C++ strings.
//
// 2) every toplevel needs its own CdlInterpreter. The application
// code should supply this interpreter itself when the toplevel
// is instantiated, allowing it to decide whether or not Tk should
// be available.
//
// 3) each loadable gets its own safe slave interpreter, derived from
// the toplevel's interpreter.
// NOTE: initially the slave interpreters are not actually safe. It
// is not clear in the long term to what extent per-loadable
// interpreters need to be sandboxes, there are issues such as
// doing the equivalent of autoconf tests.
// Tcl 8.4 involved various incompatible API changes related to
// const vs. non-const data. #define'ing USE_NON_CONST or
// USE_COMPAT_CONST avoids some of the problems, but does not
// help much for C++.
#if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))
# define CDL_TCL_CONST_CAST(type,var) (var)
#else
# define CDL_TCL_CONST_CAST(type,var) const_cast<type>(var)
#endif
class CdlInterpreterBody
{
friend class CdlTest;
public:
CYGDBG_DECLARE_MEMLEAK_COUNTER();
// This is how a top-level (i.e. per-toplevel) interpreter
// should get created.
static CdlInterpreter make(Tcl_Interp* = 0);
// Create a slave interpreter for reading in the data in e.g. a
// cdl_package
CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true);
// Make the interpreter safe, a one-way operation.
void make_safe();
// The destructor is public.
virtual ~CdlInterpreterBody();
// Add or remove commands from an interpreter. This provides
// a more C++-friendly implementation of Tcl's
// CreateCommand() and DeleteCommand().
void add_command(std::string, CdlInterpreterCommand);
void remove_command(std::string);
// In the libcdl world it is also convenient to swap whole sets of
// commands in and out. This is achieved by push and pop operations.
// push returns the old set (0 at the toplevel). pop restores
// the old set.
std::vector<CdlInterpreterCommandEntry>* push_commands(std::vector<CdlInterpreterCommandEntry>&);
void pop_commands(std::vector<CdlInterpreterCommandEntry>*);
std::vector<CdlInterpreterCommandEntry>* get_pushed_commands() const;
// Similarly, allow variables to be set, unset and queried
void set_variable(std::string, std::string);
void unset_variable(std::string);
std::string get_variable(std::string);
// FIXME: add support for variable traces. These are needed
// for cdl_value and similar utilities.
// Provide hooks into the AssocData() facilities associated with
// Tcl interpreters. This makes it possible to store arbitrary
// data with an interpreter, e.g. to keep track of current state.
void set_assoc_data(const char*, ClientData, Tcl_InterpDeleteProc* =0);
void delete_assoc_data(const char*);
ClientData get_assoc_data(const char*);
// Evaluate a string as Tcl code. The return value comes from Tcl, e.g.
// TCL_OK or TCL_ERROR. There are variants depending on whether or not
// the result string is of interest.
int eval(std::string);
int eval(std::string, std::string&);
// Ditto for any Tcl code that comes from CDL files
int eval_cdl_code(const cdl_tcl_code);
int eval_cdl_code(const cdl_tcl_code, std::string&);
// And support for evaluating an entire file
int eval_file(std::string);
int eval_file(std::string, std::string&);
// For use by commands implemented in C++, a way of setting the result
void set_result(std::string);
// And a utility to get the result as well.
std::string get_result();
// Was the result set by the Tcl interpreter or by libcdl?
bool result_set_by_cdl();
// A utility to quote data that is going to end up in a TCL script.
static std::string quote(std::string);
// Turn some multiline data into a comment.
static std::string multiline_comment(const std::string&, int, int = 0);
// Add some data to a comment, allowing for newlines if necessary
static std::string extend_comment(const std::string&, int, int = 0);
// Write some data to a savefile, throwing an exception on error
void write_data(Tcl_Channel, std::string);
// File-related utilities.
void locate_subdirs(std::string, std::vector<std::string>&);
void locate_all_subdirs(std::string, std::vector<std::string>&);
void locate_files(std::string, std::vector<std::string>&);
void locate_all_files(std::string, std::vector<std::string>&);
bool is_directory(std::string);
bool is_file(std::string);
// When parsing a CDL script it is convenient to keep track of
// a number of items:
//
// 1) the toplevel, e.g. the entire configuration
// 2) the loadable, e.g. the current package
// 3) the parent of whatever is being processed at the moment
// 4) the entity, i.e. the thingamajig that is being processed.
// 5) the current file
// 6) an error reporting function
//
// This gives the various commands embedded in the Tcl interpreter
// enough information to do their job. Additional information can
// be provided via assoc_data()
//
// There should be only one call to set_toplevel(), for the
// master interpreter. All slaves inherit this, and the toplevel
// cannot be changed again.
//
// The loadable field is filled in via make_slave()
//
// For some members push and pop functions are more appropriate
// than set.
CdlToplevel get_toplevel() const;
CdlLoadable get_loadable() const;
CdlContainer get_container() const;
CdlNode get_node() const;
std::string get_context() const;
CdlDiagnosticFnPtr get_error_fn_ptr() const;
CdlDiagnosticFnPtr get_warning_fn_ptr() const;
CdlTransaction get_transaction() const;
void set_toplevel(CdlToplevel);
void set_transaction(CdlTransaction);
CdlContainer push_container(CdlContainer);
void pop_container(CdlContainer);
CdlNode push_node(CdlNode);
void pop_node(CdlNode);
std::string push_context(std::string);
void pop_context(std::string);
CdlDiagnosticFnPtr push_error_fn_ptr(CdlDiagnosticFnPtr);
void pop_error_fn_ptr(CdlDiagnosticFnPtr);
CdlDiagnosticFnPtr push_warning_fn_ptr(CdlDiagnosticFnPtr);
void pop_warning_fn_ptr(CdlDiagnosticFnPtr);
// Provide utility classes for common push/pop combinations. The
// push happens during the constructor, the pop during the
// destructor. This can simplify some code, especially when
// exceptions may get thrown.
class DiagSupport {
public:
DiagSupport(CdlInterpreter interp_arg, CdlDiagnosticFnPtr error_fn_arg, CdlDiagnosticFnPtr warn_fn_arg) {
interp = interp_arg;
saved_error_fn = interp->push_error_fn_ptr(error_fn_arg);
saved_warn_fn = interp->push_warning_fn_ptr(warn_fn_arg);
}
~DiagSupport() {
interp->pop_error_fn_ptr(saved_error_fn);
interp->pop_warning_fn_ptr(saved_warn_fn);
}
private:
DiagSupport();
CdlInterpreter interp;
CdlDiagnosticFnPtr saved_error_fn;
CdlDiagnosticFnPtr saved_warn_fn;
};
class ContextSupport {
public:
ContextSupport(CdlInterpreter interp_arg, std::string context) {
interp = interp_arg;
saved_context = interp->push_context(context);
}
~ContextSupport() {
interp->pop_context(saved_context);
}
private:
ContextSupport();
CdlInterpreter interp;
std::string saved_context;
};
class ContainerSupport {
public:
ContainerSupport(CdlInterpreter interp_arg, CdlContainer container) {
interp = interp_arg;
saved_container = interp->push_container(container);
}
~ContainerSupport() {
interp->pop_container(saved_container);
}
private:
ContainerSupport();
CdlInterpreter interp;
CdlContainer saved_container;
};
class NodeSupport {
public:
NodeSupport(CdlInterpreter interp_arg, CdlNode node) {
interp = interp_arg;
saved_node = interp->push_node(node);
}
~NodeSupport() {
interp->pop_node(saved_node);
}
private:
NodeSupport();
CdlInterpreter interp;
CdlNode saved_node;
};
class CommandSupport {
public:
CommandSupport(CdlInterpreter interp_arg, std::vector<CdlInterpreterCommandEntry>& commands) {
interp = interp_arg;
saved_commands = interp->push_commands(commands);
}
CommandSupport(CdlInterpreter interp_arg, CdlInterpreterCommandEntry* commands) {
unsigned int i;
for (i = 0; 0 != commands[i].command; i++) {
new_commands.push_back(commands[i]);
}
interp = interp_arg;
saved_commands = interp->push_commands(new_commands);
}
~CommandSupport() {
interp->pop_commands(saved_commands);
}
private:
CommandSupport();
CdlInterpreter interp;
std::vector<CdlInterpreterCommandEntry>* saved_commands;
std::vector<CdlInterpreterCommandEntry> new_commands;
};
// Similar utility classes for variables and assoc data.
class VariableSupport {
public:
VariableSupport(CdlInterpreter interp_arg, std::string varname_arg, std::string data) {
interp = interp_arg;
varname = varname_arg;
interp->set_variable(varname, data);
}
~VariableSupport() {
interp->unset_variable(varname);
}
private:
VariableSupport();
CdlInterpreter interp;
std::string varname;
};
class AssocSupport {
public:
AssocSupport(CdlInterpreter interp_arg, const char* name_arg, ClientData data, Tcl_InterpDeleteProc* del_proc = 0) {
interp = interp_arg;
name = name_arg;
interp->set_assoc_data(name, data, del_proc);
}
~AssocSupport() {
interp->delete_assoc_data(name);
}
private:
AssocSupport();
CdlInterpreter interp;
const char* name;
};
// Some command implementations may want to access other Tcl library
// routines such as Tcl_SplitList(). This requires convenient access
// to the underlying Tcl interpreter.
Tcl_Interp* get_tcl_interpreter() const;
// For use by the assertion macros.
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
private:
// This is the Tcl command proc that gets registered for all
// CdlInterpreterCommand instances.
static int tcl_command_proc(ClientData, Tcl_Interp*, int, const char*[]);
// This key is used to access the CdlInterpreter assoc data.
static char* cdlinterpreter_assoc_data_key;
// Do not allow static instances of a Cdl interpreter. There are too
// many possible failure conditions. Cdl interpreters can only be
// created dynamically via make(), which will invoke this.
CdlInterpreterBody(Tcl_Interp*);
// Default constructor, copy constructor and assignment are illegal
CdlInterpreterBody();
CdlInterpreterBody(const CdlInterpreterBody&);
CdlInterpreterBody& operator=(const CdlInterpreterBody&);
Tcl_Interp* tcl_interp; // The underlying Tcl interpreter
bool owns_interp; // Was the Tcl interpreter created by the library?
std::vector<CdlInterpreter> slaves; // All slave interpreters
CdlInterpreter parent; // Or else the parent
CdlToplevel toplevel; // Data that gets used during the parsing process
CdlTransaction transaction;
CdlLoadable loadable;
CdlContainer container;
CdlNode node;
std::string context;
CdlDiagnosticFnPtr error_fn_ptr;
CdlDiagnosticFnPtr warning_fn_ptr;
bool cdl_result;
std::vector<CdlInterpreterCommandEntry>* current_commands; // for push() and pop()
enum {
CdlInterpreterBody_Invalid = 0,
CdlInterpreterBody_Magic = 0x0be67689
} cdlinterpreterbody_cookie;
};
//}}}
//{{{ CdlReference/Referrer classes
// ---------------------------------------------------------------------------
// CDL objects are organised primarily in a tree hierarchy. For
// example a package contains components, components contain options,
// and so on. The tree hierarchy tends to change rather infrequently,
// so it makes sense to have a quick way of navigating between
// entities without continuously having to do hash-table lookups. In
// addition it is very desirable to make the connectivity
// bidirectional: if a "requires" property in option A references
// option B then it would be useful to have a link back to A from B;
// that way, if the value of B changes it is a lot easier to keep
// things up to date.
//
// Terminology: the entity which contains the reference, e.g. a
// "requires" property, is the source. The relevant property is the
// "source property". The entity pointed at is the destination.
//
// Unfortunately there may be connections between CDL entities outside
// the tree hierarchy. In particular any property can contain one or
// more references to packages, components, options, wizards, or
// whatever. Often these references will be to options etc. within the
// same package, but some references will go to other packages. There
// may even be references to other configurations: for example a board
// may contain both an ordinary processor and a DSP; these two need
// their own configurations; however a package running on the DSP may
// need to interact with a package running on the processor, and vice
// versa.
//
// Also, a reference may occur inside an object that is not in the
// hierarchy. For example CDL expressions may get evaluated inside Tcl
// code rather than as part of a property. Such expressions may still
// contain references to entities in the current configuration.
//
// References may not be resolved. When reading in a CDL script there
// may be forward references. A reference may involve another package
// that has not yet been loaded, which is a conflict.
//
// Using simple pointers to store these connections is a bad idea. It
// makes it a lot harder to figure out what is connected to what, and
// it introduces horrible consistency problems when packages get
// loaded and unloaded. Instead libCDL provides a CdlReference class.
// Whenever a CdlProperty contains a reference to some other CDL
// entity there should be a CdlReference object corresponding to this.
// The reverse direction is handled via a CdlReferrer object.
//
// A CdlReference object can be either bound or unbound. By default it
// is unbound, containing only a string. It can then be bound via a
// member function, examined, and unbound again as required. Creating
// a binding automatically creates a CdlReferrer entry in the target
// object, thus avoiding any risk of inconsistencies.
//
// The CdlReference class should not be used outside the hierarchy,
// since every bound reference must have a referrer object pointing
// back, and this link back can only be valid within the hierarchy.
// Temporary CdlReference objects are useful during the construction
// of properties.
//
// It is possible that a given property (e.g. a complicated "requires"
// expression) has multiple references to another entity. Each of
// these involves a separate CdlReference/CdlReferrer pair.
// ----------------------------------------------------------------------------
// The actual CdlReference class.
class CdlReference {
friend class CdlTest;
// CdlReferrer must be a friend so that when a package gets unloaded
// it can clean up all references to it.
friend class CdlReferrer;
public:
// The default constructor should not normally be used, instead
// a string should be supplied. However there are vectors of
// reference objects...
CdlReference();
// The main constructor supplies the name of the referenced
// entity. The resulting object will be unbound.
CdlReference(const std::string);
// The copy constructor is legal for unbound objects only.
CdlReference(const CdlReference&);
// The assignment operator is needed for STL operations.
// Again it only makes sense of unbound objects.
CdlReference& operator=(const CdlReference&);
// The destructor is only valid for unbound objects. All references
// should be unbound before an entity can be destroyed.
~CdlReference();
// Access the various fields.
void set_destination_name(const std::string);
const std::string& get_destination_name() const;
CdlNode get_destination() const;
// Binding a reference. Obviously this can only be used when the
// reference is still unbound. When doing the binding it is
// necessary to know:
// (1) the object containing the reference.
// (2) the specific property that contains the reference.
// (3) the object being referred to.
// Binding a reference results in a new referrer entry in the
// destination.
void bind(CdlNode, CdlProperty, CdlNode);
// Unbinding a reference. Typically this only happens when the
// destination is unloaded. The arguments provide the source and
// the source property.
void unbind(CdlNode, CdlProperty);
// This is used by the ASSERT_CLASS() and ASSERT_THIS() macros.
bool check_this(cyg_assert_class_zeal cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
// The data fields. The name is usually filled in by the
// constructor. The destination defaults to zero for an unbound
// object and gets filled in by the bind() operation.
std::string dest_name;
CdlNode dest;
enum {
CdlReference_Invalid = 0,
CdlReference_Magic = 0x3f908608
} cdlreference_cookie;
};
// ----------------------------------------------------------------------------
// The CdlNode class (and hence just about everything) contains a
// vector of CdlReferrer objects. This keeps track of all entities
// that refer to this one, so if the value associated with this
// changes it is possible to work out the impact of this on all
// entities that rely on this value.
//
// Arguably this should work in terms of CdlValuable objects rather
// than CdlNode objects. However it is convenient to use references
// for the connection between e.g. an option and a dialog, where
// there is no value involved. The reverse connection is of little
// use in this circumstance.
//
// CdlReferrer objects are rarely accessed directly. Instead they will
// be filled in during a CdlReference::bind() operation and erased
// during a CdlReference::unbind() operation. The only operations that
// should be public allow access to the contained data.
class CdlReferrer {
friend class CdlTest;
// CdlReference::bind() and unbind() have direct access to the
// members, since these two functions are really responsible for
// creating and destroying referrer objects.
friend class CdlReference;
public:
// The default constructor, copy constructor and assignment
// operator are all public to avoid problems with having vectors
// of referrer objects. Similarly the destructor is public.
// In practice updates actually happen as a consequence of
// CdlReference::bind() and CdlReference::unbind().
CdlReferrer();
CdlReferrer(const CdlReferrer&);
CdlReferrer& operator=(const CdlReferrer&);
~CdlReferrer();
CdlNode get_source() const;
CdlProperty get_source_property() const;
void update(CdlTransaction, CdlNode, CdlUpdate);
bool check_this(cyg_assert_class_zeal=cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
CdlNode source;
CdlProperty source_property;
enum {
CdlReferrer_Invalid = 0,
CdlReferrer_Magic = 0x70e1fc37
} cdlreferrer_cookie;
};
//}}}
//{{{ Value and Expression classes
//{{{ CdlEvalContext
// ----------------------------------------------------------------------------
// Expression evaluation always happens within a certain context.
// This may involve a transaction. Usually it involves a node and
// a property within that node, although it is possible to evaluate
// expressions from inside Tcl code.
//
// To avoid passing too many arguments around the various
// evaluation-related routines, a utility class is provided.
class CdlEvalContext {
friend class CdlTest;
public:
CdlTransaction transaction;
CdlNode node;
CdlProperty property;
CdlToplevel toplevel;
CdlEvalContext(CdlTransaction, CdlNode = 0, CdlProperty = 0, CdlToplevel = 0);
~CdlEvalContext();
// Given a reference inside an expression, try to resolve this to either
// a node or, more specifically, a valuable.
CdlNode resolve_reference(CdlExpression, int);
CdlValuable resolve_valuable_reference(CdlExpression, int);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
// Illegal operation, the three fields must always be supplied,
// although they may be zero.
CdlEvalContext();
enum {
CdlEvalContext_Invalid = 0,
CdlEvalContext_Magic = 0x03434be9
} cdlevalcontext_cookie;
};
//}}}
//{{{ CdlSimpleValue
// ----------------------------------------------------------------------------
// Expression evaluation happens in terms of CdlSimpleValue objects.
// In CDL all values are strings, but for the purposes of arithmetic
// these strings sometimes have to be interpreted as integers or as
// double precision numbers. Sometimes there is a choice, for example
// the equality operator == can mean numerical or string comparison.
// The basic rules that get applied are:
//
// 1) if the current value has an integer representation then
// use this by preference. This means that an expression
// of the form (CYGNUM_XXX != 0x100) will do a integer
// comparison if possible.
//
// 2) otherwise if the current value can be interpreted as a
// double precision number, use that representation.
// All integers can be interpreted as doubles (at the risk
// of some loss of precision), so the representation as
// a double should only be used if the integer representation
// is inappropriate.
//
// 3) otherwise interpret the value as a string.
//
// The default value is 0.
class CdlSimpleValue {
friend class CdlTest;
public:
CdlSimpleValue();
CdlSimpleValue(std::string);
CdlSimpleValue(cdl_int);
CdlSimpleValue(double);
CdlSimpleValue(const CdlSimpleValue&);
CdlSimpleValue(bool);
~CdlSimpleValue();
CdlSimpleValue& operator=(const CdlSimpleValue&);
CdlSimpleValue& operator=(std::string);
CdlSimpleValue& operator=(cdl_int);
CdlSimpleValue& operator=(double);
CdlSimpleValue& operator=(bool);
bool operator==(const CdlSimpleValue&) const;
bool operator!=(const CdlSimpleValue&) const;
bool operator==(std::string arg) const
{
CdlSimpleValue val(arg);
return *this == val;
}
bool operator==(cdl_int arg) const
{
CdlSimpleValue val(arg);
return *this == val;
}
bool operator==(double arg) const
{
CdlSimpleValue val(arg);
return *this == val;
}
bool operator!=(std::string arg) const
{
CdlSimpleValue val(arg);
return *this != val;
}
bool operator!=(cdl_int arg) const
{
CdlSimpleValue val(arg);
return *this != val;
}
bool operator!=(double arg) const
{
CdlSimpleValue val(arg);
return *this != val;
}
void set_value(std::string, CdlValueFormat = CdlValueFormat_Default);
std::string get_value() const;
bool has_integer_value() const;
void set_integer_value(cdl_int, CdlValueFormat = CdlValueFormat_Default);
cdl_int get_integer_value() const;
bool has_double_value() const;
void set_double_value(double, CdlValueFormat = CdlValueFormat_Default);
double get_double_value() const;
CdlValueFormat get_value_format() const;
void set_value_format(CdlValueFormat);
void set_value_format(CdlSimpleValue&);
void set_value_format(CdlSimpleValue&, CdlSimpleValue&);
static void eval_valuable(CdlEvalContext&, CdlValuable, CdlSimpleValue&);
// For expression evaluation, it is often convenient to get hold
// of a boolean as well. This may indicate a non-empty string
// or a non-zero value.
bool get_bool_value() const;
// This class is too simple to warrant even a cookie validation.
bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const {
return true;
}
protected:
private:
enum {
int_valid = 0x01,
double_valid = 0x02,
string_valid = 0x04,
int_invalid = 0x08,
double_invalid = 0x10
};
mutable int valid_flags;
mutable std::string value;
mutable cdl_int int_value;
mutable double double_value;
CdlValueFormat format;
};
//}}}
//{{{ CdlListValue
// ----------------------------------------------------------------------------
// Evaluating a list expression results in a set of possible values, but
// unlike the original list expression these values are now constant and
// can have no dependencies on CDL entities. As with list expressions the
// main operation on a list value is to detect membership, but using
// list values allows multiple potential members to be tested without
// repeated expression evaluation. The main use of list values is implicit
// in libcdl, each list expression contains a mutable cached list value.
//
// A list value contains five sets of data:
//
// 1) separate vectors of strings, integers, and floating point constants.
// Having separate vectors of integers and floating points avoids
// problems when numbers can be represented in different formats.
// 2) a vector of cdl_int pairs for ranges of integer data
// 3) a vector of double pairs for ranges of floating point data
//
// Any of these vectors may be empty, but at least one of the vectors should
// contain useful data. Possibly there should also be tables for cdl_int and
// double to avoid unnecessary string conversions.
class CdlListValue {
friend class CdlTest;
// A list value will only be filled in when a list expression is evaluated.
// The members cannot be updated by other means.
friend class CdlListExpressionBody;
public:
CdlListValue();
~CdlListValue();
CdlListValue(const CdlListValue&);
CdlListValue& operator=(const CdlListValue&);
bool is_member(CdlSimpleValue&) const;
bool is_member(std::string, bool = true) const;
bool is_member(cdl_int, bool = true) const;
bool is_member(double, bool = true) const;
// These provide access to the raw data, for example if it is
// necessary to suggest a legal value to the user.
const std::vector<CdlSimpleValue>& get_table() const;
const std::vector<std::pair<cdl_int, cdl_int> >& get_integer_ranges() const;
const std::vector<std::pair<double, double> >& get_double_ranges() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
std::vector<CdlSimpleValue> table;
std::vector<std::pair<cdl_int, cdl_int> > integer_ranges;
std::vector<std::pair<double, double> > double_ranges;
enum {
CdlListValue_Invalid = 0,
CdlListValue_Magic = 0x2183a943
} cdllistvalue_cookie;
};
//}}}
//{{{ CdlValue
// ----------------------------------------------------------------------------
// Values in CDL are non-trivial compared with some other languages.
// Even though CDL is not a fully-typed language, it does still have
// four different flavors to consider. There is also the problem that
// an entity may have up to four different values which should be
// stored (default, inferred, wizard, user), with the ability to
// switch between them. The CdlValue class provides support for this.
//
// CdlValue objects are not normally updated explicitly. Instead
// higher level code deals with CdlValuable objects, which inherit
// privately from CdlValue. Modifications to CdlValuables happen in
// the context of a transaction.
//
// The first concept to take into account is the flavor. There
// are four flavors, None, Bool, BoolData and Data. The member
// function get_flavor() can be used to obtain the current flavor.
//
// CdlValueFlavor CdlValue::get_flavor() const;
//
// Values may be enabled or disabled. Values of flavor None
// and Data are always enabled. Values of flavor Bool or BoolData
// may or may not be enabled, by default they are disabled.
//
// bool CdlValue::is_enabled(...) const;
//
// (The optional argument to is_enabled() is discussed later).
//
// Values of flavor BoolData and Data also have a string value,
// which can be interpreted as an integer or a double under
// the right circumstances.
//
// std::string CdlValue::get_value(...) const;
// bool CdlValue::has_integer_value(...) const;
// bool CdlValue::has_double_value(...) const;
// cdl_int CdlValue::get_integer_value(...) const;
// double CdlValue::get_double_value(...) const;
//
// This is equivalent to a CdlSimpleValue object, and in fact
// that is the internal representation. It is possible to
// get hold of the CdlSimpleValue object directly:
//
// CdlSimpleValue CdlValue::get_simple_value(...) const;
//
// The get_integer_value() and get_double_value() members should
// only be used if you are confident that the current value has
// an integer or double representation. Otherwise the result is
// undefined.
//
// The optional argument to these member functions represents
// the source. A value can be set from four different sources:
// the default value (usually either 0 or the result of
// evaluating a default_value property); an inferred value,
// determined by the inference engine; a wizard value, i.e.
// what a CDL wizard believes the correct value to be based
// on user input; and a user value, something explicitly
// set by the end user. These have different priorities:
// the inference engine can override default values but not
// user values. A CdlValue object keeps track of the current
// source.
//
// CdlValueSource CdlValue::get_source() const;
//
// If no argument is given to e.g. is_enabled() then the
// current source is used. Otherwise it is possible to find
// out whether or not the entity is enabled for each of the
// sources.
//
// The default source is always defined, the others may or
// may not be. It is possible to find out for each source
// whether or not a value has been set.
//
// bool CdlValue::has_source(CdlValueSource) const;
//
//
// Updating values normally happens in the CdlValuable class,
// but the member functions are the same. There is a member
// function to change the flavor:
//
// void CdlValue::set_flavor(CdlValueFlavor);
//
// However this member function is intended only for use by the
// library itself. An entity's flavor is normally defined by CDL data,
// and should not be updated explicitly by application code.
//
// There are two member functions to manipulate the value source:
//
// void CdlValue::set_source(CdlValueSource);
// void CdlValue::invalidate_source(CdlValueSource);
//
// The first function can be used if e.g. the user wants to
// change his or her mind and go back to the default value
// rather than a user value. The user value is not forgotten
// and can be reinstated.
//
// invalidate_source() can be used to completely cancel a
// value source. If that source happens to be the current one
// then the current source will be adjusted appropriately.
// It is illegal to attempt to invalidate the default source.
//
// For values with flavor Bool and BoolData, there are three
// member functions that can be used to control the enabled
// status:
//
// void CdlValue::set_enabled(bool, CdlValueSource);
// void CdlValue::enable(CdlValueSource);
// void CdlValue::disable(CdlValueSource);
//
// Note that when updating a CdlValue object the source should
// be known and must be specified. If the source has a higher
// priority than the current one then it will automatically
// become the new source. On the rare occasion that this is
// not desired, set_source() will have to be used afterwards
// to reset the current source.
//
// For values with flavor BoolData and Data the following
// member functions are available to change the value string:
//
// void CdlValue::set_value(std::string, CdlValueSource);
// void CdlValue::set_value(cdl_int, CdlValueSource);
// void CdlValue::set_value(double, CdlvalueSource);
// void CdlValue::set_value(CdlSimpleValue&, CdlValueSource);
//
// For values with flavor BoolData is is possible to
// combine updating the enabled flag and the string value:
//
// void CdlValue::set_enabled_and_value(bool, std::string, CdlValueSource);
// void CdlValue::set_enabled_and_value(bool, cdl_int, CdlValueSource);
// void CdlValue::set_enabled_and_value(bool, double, CdlValueSource);
// void CdlValue::set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
// void CdlValue::enable_and_set_value(std::string, CdlValueSource);
// void CdlValue::enable_and_set_value(cdl_int, CdlValueSource);
// void CdlValue::enable_and_set_value(double, CdlValueSource);
// void CdlValue::enable_and_set_value(CdlSimpleValue&, CdlValueSource);
// void CdlValue::disable_and_set_value(std::string, CdlValueSource);
// void CdlValue::disable_and_set_value(cdl_int, CdlValueSource);
// void CdlValue::disable_and_set_value(double, CdlValueSource);
// void CdlValue::disable_and_set_value(CdlSimpleValue&, CdlValueSource);
//
// Obviously many of these functions are just simple inlines.
//
// There is one final member function:
//
// void CdlValue::set(CdlSimpleValue, CdlValueSource);
//
// This member function is defined to do the right thing,
// whatever the flavor happens to be.
class CdlValue {
friend class CdlTest;
public:
CdlValue(CdlValueFlavor = CdlValueFlavor_Bool);
virtual ~CdlValue();
CdlValue(const CdlValue&);
CdlValue& operator=(const CdlValue&);
CdlValueFlavor get_flavor() const;
CdlValueSource get_source() const;
bool has_source(CdlValueSource) const;
bool is_enabled(CdlValueSource = CdlValueSource_Current) const;
std::string get_value(CdlValueSource = CdlValueSource_Current) const;
bool has_integer_value(CdlValueSource = CdlValueSource_Current) const;
bool has_double_value(CdlValueSource = CdlValueSource_Current) const;
cdl_int get_integer_value(CdlValueSource = CdlValueSource_Current) const;
double get_double_value(CdlValueSource = CdlValueSource_Current) const;
CdlSimpleValue get_simple_value(CdlValueSource = CdlValueSource_Current) const;
void set_source(CdlValueSource);
void invalidate_source(CdlValueSource);
void set_enabled(bool, CdlValueSource);
void enable(CdlValueSource source)
{
set_enabled(true, source);
}
void disable(CdlValueSource source)
{
set_enabled(false, source);
}
void set_value(CdlSimpleValue&, CdlValueSource);
void set_value(std::string data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(val, source);
}
void set_integer_value(cdl_int data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(val, source);
}
void set_double_value(double data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(val, source);
}
void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(enabled, val, source);
}
void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(enabled, val, source);
}
void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(enabled, val, source);
}
void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
{
set_enabled_and_value(true, val, source);
}
void enable_and_set_value(std::string data, CdlValueSource source)
{
set_enabled_and_value(true, data, source);
}
void enable_and_set_value(cdl_int data, CdlValueSource source)
{
set_enabled_and_value(true, data, source);
}
void enable_and_set_value(double data, CdlValueSource source)
{
set_enabled_and_value(true, data, source);
}
void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
{
set_enabled_and_value(false, val, source);
}
void disable_and_set_value(std::string data, CdlValueSource source)
{
set_enabled_and_value(false, data, source);
}
void disable_and_set_value(cdl_int data, CdlValueSource source)
{
set_enabled_and_value(false, data, source);
}
void disable_and_set_value(double data, CdlValueSource source)
{
set_enabled_and_value(false, data, source);
}
void set(CdlSimpleValue&, CdlValueSource);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
// This should only be used by the library itself.
void set_flavor(CdlValueFlavor);
protected:
private:
CdlValueFlavor flavor;
CdlValueSource current_source;
// FIXME: a static const member should be used for the array
// sizes, but VC++ does not support that part of the language.
// FIXME: std::bitset should be used here. Using lots of separate
// bools here is inefficient.
bool source_valid[4];
bool enabled[4];
CdlSimpleValue values[4];
enum {
CdlValue_Invalid = 0,
CdlValue_Magic = 0x41837960
} cdlvalue_cookie;
};
//}}}
//{{{ CdlSubexpression
// ----------------------------------------------------------------------------
// Expressions come into existence primarily as the result of reading
// in certain properties like default_value in CDL data. It is also
// possible for expressions to be generated and evaluated on the fly
// inside Tcl code, but that is expected to be a comparatively rare
// events. Expression objects always live on the heap, usually only
// in derived classes.
//
// An ordinary expression evaluates to a single value. There are two
// other types of expression in the CDL language, goal expressions and
// list expression. A goal expression is essentially a set of ordinary
// expressions with implicit &&'s between them. A list expression
// is a set of expressions that can be evaluated to a constant vector,
// plus pairs of expressions that constitute ranges. Again goal and
// list expressions only live on the heap.
//
// Both parsing an evaluation involve tokens for the various
// operators. The inference engine, conflict reporting code, and
// other diagnostic code will also need to have ready access to
// this information. Hence it makes a bit more sense to have
// the enum outside the expression class.
enum CdlExprOp {
CdlExprOp_Invalid = 0,
CdlExprOp_EOD = 1, // End of data reached
CdlEXprOp_Command = 2, // [tcl code]
CdlExprOp_Variable = 3, // $tcl_variable
CdlExprOp_StringConstant = 4, // "hello"
CdlExprOp_IntegerConstant = 5, // 123
CdlExprOp_DoubleConstant = 6, // 3.1415
CdlExprOp_Reference = 7, // CYGPKG_INFRA
CdlExprOp_Range = 8, // x to y
CdlExprOp_Negate = 9, // -x
CdlExprOp_Plus = 10, // +x
CdlExprOp_LogicalNot = 11, // !x
CdlExprOp_BitNot = 12, // ~x
CdlExprOp_Indirect = 13, // *x
CdlExprOp_Active = 14, // ?x
CdlExprOp_Function = 15, // sin(x)
CdlExprOp_Multiply = 16, // x * y
CdlExprOp_Divide = 17, // x / y
CdlExprOp_Remainder = 18, // x % y
CdlExprOp_Add = 19, // x + y
CdlExprOp_Subtract = 20, // x - y
CdlExprOp_LeftShift = 21, // x << y
CdlExprOp_RightShift = 22, // x >> y
CdlExprOp_LessThan = 23, // x < y
CdlExprOp_LessEqual = 24, // x <= y
CdlExprOp_GreaterThan = 25, // x > y
CdlExprOp_GreaterEqual = 26, // x >= y
CdlExprOp_Equal = 27, // x == y
CdlExprOp_NotEqual = 28, // x != y
CdlExprOp_BitAnd = 29, // x & y
CdlExprOp_BitXor = 30, // x ^ y
CdlExprOp_BitOr = 31, // x | y
CdlExprOp_And = 32, // x && y
CdlExprOp_Or = 33, // x || y
CdlExprOp_Cond = 34, // x ? a : b
CdlExprOp_StringConcat = 35, // x . y
CdlExprOp_Implies = 36, // x implies y
CdlExprOp_Xor = 37, // x xor y
CdlExprOp_Eqv = 38 // x eqv y
};
// ----------------------------------------------------------------------------
// A subexpression consists of an operation, possibly some constant
// data, and possibly indices into the subexpression vector.
// Normally some unions would be used, but unions and objects such
// as std::string do not mix, and the amount of memory involved is
// not big enough to really worry about.
#define CdlFunction_MaxArgs 3
struct CdlSubexpression {
CdlExprOp op;
CdlSimpleValue constants; // String, integer or double constant
int reference_index; // iff CdlExprOp_Reference
int lhs_index; // for all non-constant operators
int rhs_index; // for binary and ternary operators only
int rrhs_index; // only for ternary operators.
int func; // iff CdlExprOp_Function
int args[CdlFunction_MaxArgs];
};
//}}}
//{{{ CdlFunction
// ----------------------------------------------------------------------------
// Generic support for function parsing, evaluation, and inference. The
// implementation is extensible so that functions can be added to the
// core via static constructors.
class CdlFunction {
friend class CdlTest;
public:
CdlFunction(const char* /* name */, int /* no_args */,
void (*)(CdlExpression, const CdlSubexpression&),
void (*)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&),
bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int),
bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)
);
~CdlFunction();
static bool is_function(std::string, int&);
static std::string get_name(int);
static int get_args_count(int);
static void check(CdlExpression, const CdlSubexpression&);
static void eval(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
static bool infer_bool(CdlTransaction, CdlExpression, unsigned int, bool, int);
static bool infer_value(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
static void (*null_check)(CdlExpression, const CdlSubexpression&);
static bool (*null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int);
static bool (*null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
protected:
private:
// Keep track of all functions in the system
static std::vector<CdlFunction*> all_functions;
// Each function object is given a unique id during initialization
static int next_id;
int id;
// Provided by the constructor
const char* name;
int number_args;
void (*check_fn)(CdlExpression, const CdlSubexpression&);
void (*eval_fn)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
bool (*infer_bool_fn)(CdlTransaction, CdlExpression, unsigned int, bool, int);
bool (*infer_value_fn)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
// The default constructor is illegal
CdlFunction();
};
//}}}
//{{{ CdlExpression
// ----------------------------------------------------------------------------
// And now for the expression class itself.
class CdlExpressionBody {
friend class CdlTest;
public:
// The default constructor is basically a no-op, new expression
// objects only get created as a consequence of parsing. However
// it exists and is protected for the convenience of derived
// classes. The copy constructor is protected, allowing parsing
// code to first parse an expression and then copy the expression
// into a higher level object. The assignment operator is illegal.
// There is no reason to hide the destructor.
virtual ~CdlExpressionBody();
// An expression involves three pieces of data. There is a vector
// of subexpressions. It is also necessary to know where
// evaluation should being, in accordance with operator precedence
// rules. And there is a vector of CdlReference objects - this
// needs to be kept separate from the subexpression vector because
// CdlReference objects are comparatively tricky.
//
// All of this data is public and can be readily inspected by the
// inference engine, by conflict detection code, by diagnostic
// code, etc.
std::vector<CdlSubexpression> sub_expressions;
int first_subexpression;
std::vector<CdlReference> references;
bool update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
// There are a number of parsing functions. The first one is
// used by higher-level code to parse a single expression. Its
// argument is a single string (which may be the result of
// concatenating several Tcl arguments), and at the end of the
// parse operation there should be no further data. The result
// will either be a new expression object or a parsing exception
// to be caught by higher level code.
static CdlExpression parse(std::string);
// This is used when parsing list expressions, which involve a
// sequence of ordinary expressions and possibly range operators.
// The whole list expression lives in a single string, and it is
// necessary to provide an index indicating where in the string
// parsing should begin. It is also useful to return details of
// the token that caused parsing to terminate (EOD, Range, or
// the start of something else).
static CdlExpression parse(std::string, int&, CdlExprOp&, int&);
// A goal expression is derived from an ordinary expression but
// has somewhat different rules for evaluating. Parsing a goal
// expression involves parsing a number of ordinary expressions
// with implicit && operators between them, and it requires
// a parsing function that can be used to extend an existing
// expression.
//
// NOTE: possibly this should should be a protected member, since
// its main use is in parsing goal expressions.
static void continue_parse(CdlExpression, std::string, int&, CdlExprOp&, int&);
// Evaluating expressions. Note that this may fail at run-time
// because of errors that cannot be caught sensibly when the
// expression is read in, for example arithmetic overflow or
// division by zero. Because such failures are a possibility
// anyway no special action is taken to prevent an expression
// with e.g. an unresolved reference from being evaluated.
//
// eval() is the public interface, and manages
// CdlConflict_EvalException objects. eval_internal() is for use
// by list and goal expressions.
void eval(CdlEvalContext&, CdlSimpleValue&);
void eval_internal(CdlEvalContext&, CdlSimpleValue&);
void eval_subexpression(CdlEvalContext&, int, CdlSimpleValue&);
// The full original expression is useful for diagnostics purposes
std::string get_original_string() const;
bool check_this(cyg_assert_class_zeal cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
// The default constructor does very little, the main work
// is done by the various parsing functions. However it is
// available to derived classes, especially goal expressions.
CdlExpressionBody();
// The copy constructor has to be usable by derived classes,
// e.g. CdlExpressionProperty
CdlExpressionBody(const CdlExpressionBody&);
private:
// The assignment operator is illegal.
CdlExpressionBody& operator=(const CdlExpressionBody&);
// The string that was parsed originally
std::string expression_string;
enum {
CdlExpressionBody_Invalid = 0,
CdlExpressionBody_Magic = 0x760293a3
} cdlexpressionbody_cookie;
};
//}}}
//{{{ CdlListExpression
// ----------------------------------------------------------------------------
// The main use of list expressions is for the legal_values
// properties. Essentially a list expression is just a vector of
// ordinary expressions and ranges of expressions.
class CdlListExpressionBody {
friend class CdlTest;
public:
// Availability of constructors etc. is as per the ordinary
// expression class.
virtual ~CdlListExpressionBody();
// The data associated with a list expression is a vector of
// expressions, plus a vector of expression pairs constituting
// ranges. As with ordinary expressions the data is fully public
// and can be readily examined by e.g. the inference engine.
std::vector<CdlExpression> data;
std::vector<std::pair<CdlExpression,CdlExpression> > ranges;
// Parsing. This involves taking a single string, typically from
// a CDL script, and parsing one or more ordinary expressions.
static CdlListExpression parse(std::string);
// Evaluation support. A list expression evaluates to a list value.
void eval(CdlEvalContext&, CdlListValue&);
// More commonly client code is going to be interested in whether
// or not a particular value is a legal member. The result
// cache ensures that it is possible to
bool is_member(CdlEvalContext&, CdlSimpleValue&);
bool is_member(CdlEvalContext&, std::string);
bool is_member(CdlEvalContext&, cdl_int);
bool is_member(CdlEvalContext&, double);
// The full original expression is useful for diagnostics purposes
std::string get_original_string() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlListExpressionBody(const CdlListExpressionBody&);
bool update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
private:
CdlListExpressionBody();
CdlListExpressionBody& operator=(const CdlListExpressionBody&);
void eval_internal(CdlEvalContext&, CdlListValue&);
std::string expression_string;
enum {
CdlListExpressionBody_Invalid = 0,
CdlListExpressionBody_Magic = 0x7da4bcc2
} cdllistexpressionbody_cookie;
};
//}}}
//{{{ CdlGoalExpression
// ----------------------------------------------------------------------------
// A goal expression inherits privately from ordinary expressions. Essentially
// a goal expression is simply a set of ordinary expressions separated by &&,
// but it can only be evaluated to a boolean. The parse() and eval() members
// of the base class should not be exposed. There is a member to get hold of
// the underlying ordinary expression, for use by e.g. the inference engine.
class CdlGoalExpressionBody : private CdlExpressionBody {
friend class CdlTest;
typedef CdlExpressionBody inherited;
public:
virtual ~CdlGoalExpressionBody();
static CdlGoalExpression parse(std::string);
// A few variants of the eval() member, with a choice of returning
// by value or by reference. The latter provide consistency with the
// other expression classes.
bool eval(CdlEvalContext&);
void eval(CdlEvalContext&, bool&);
// Provide public access to the underlying expression object,
// useful for the inference engine
CdlExpression get_expression();
// The full original expression is useful for diagnostics purposes
std::string get_original_string() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlGoalExpressionBody(const CdlGoalExpressionBody&);
private:
CdlGoalExpressionBody();
CdlGoalExpressionBody& operator=(const CdlGoalExpressionBody&);
void eval_internal(CdlEvalContext&, bool&);
std::string expression_string;
enum {
CdlGoalExpressionBody_Invalid = 0,
CdlGoalExpressionBody_Magic = 0x5a58bb24
} cdlgoalexpressionbody_cookie;
};
//}}}
//{{{ CdlInfer
// ----------------------------------------------------------------------------
// A utility class related to inference. This exports the main functions
// needed, allowing e.g. per-function inference routines from func.cxx to
// interact with the main inference engine.
class CdlInfer {
public:
static bool make_active(CdlTransaction, CdlNode, int /* level */);
static bool make_inactive(CdlTransaction, CdlNode, int /* level */);
static bool set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, int /* level */);
static bool set_valuable_bool(CdlTransaction, CdlValuable, bool, int /* level */);
static bool subexpr_value(CdlTransaction, CdlExpression, unsigned int /* index */, CdlSimpleValue& goal, int /* level */);
static bool subexpr_bool(CdlTransaction, CdlExpression, unsigned int /* index */, bool, int /* level */);
private:
CdlInfer();
};
//}}}
//}}}
//{{{ CdlConflict classes
// ----------------------------------------------------------------------------
// As a configuration is created and modified there will be times when
// things are not completely consistent. There may be a reference to
// some option that is not in any package in the current
// configuration. An option may have an invalid value, possibly as a
// side effect of a change to some other option. There may be a
// dependency that is not satisfied. There may be other types of
// conflict.
//
// The library provides a base class CdlConflict, and a number of
// derived classes for common types of conflict such as unresolved
// references. All conflicts are associated with a CdlNode and a
// property within that. It is possible to use dynamic_cast<> to find
// out the exact type of a conflict, or alternatively to use the
// virtual member function get_explanation().
//
// Conflicts may be disabled by the user if they are not actually
// important as far as application code is concerned. In other words
// the end user is allowed to override the constraints specified in
// the CDL. This information is saved with the configuration data.
// Preferably the user should give an explanation for why the conflict
// is disabled, to serve as a reminder some months later when the
// configuration is reloaded.
//
//
// Conflicts have a fairly complicated life cycle. First it is
// necessary to distinguish between structural and normal conflicts. A
// structural conflict is typically caused by a reference to a
// non-existent valuable. These conflicts are generally created only
// when something is loaded, and only go away when something is
// unloaded. A normal conflict is typically related to a value, for
// example a value outside the legal range, or a "requires" property
// that is not satisfied.
//
// Conflicts are created and destroyed in the context of a
// transaction, which in turn operates in the context of a toplevel.
// If the transaction is committed then new conflicts get added to the
// appropriate toplevel list, and destroyed conflicts get removed from
// the toplevel list. The transaction field indicates whether the
// conflict is currently per-transaction or global.
//
// Transactions may get nested, i.e. a conflict may get created as
// part of a sub-transaction, and when that sub-transaction is committed
// the conflict is moved to the parent transaction.
//
// For each toplevel, libcdl keeps track of all conflicts. This only
// applies to committed conflicts, per-transaction conflicts are not
// accessible in this way.
//
// As part of a transaction, libcdl may attempt to find solutions for
// particular conflicts, and those solutions may get installed
// automatically. No attempt is made to keep track of solutions
// on a global basis, only on a per-transaction basis.
class CdlConflictBody {
friend class CdlTest;
// Transactions and conflicts are closely connected
friend class CdlTransactionBody;
public:
// Creation happens only inside a derived class.
// Clearing a conflict only happens inside transactions.
// Destroying a conflict only happens from inside a
// per-transaction clear(), or during a transaction commit.
// Is this conflict part of a transaction, or has it been committed to the toplevel.
CdlTransaction get_transaction() const;
// Is inference implemented for this type of conflict?
virtual bool resolution_implemented() const;
// Try to resolve an existing global conflict. A new transaction
// is created for this operation, the conflict is resolved within
// that transaction, and then CdlTransaction::body() is used to
// handle inference callbacks, commits, etc. See also
// CdlToplevel::resolve_conflicts() and
// CdlToplevel::resolve_all_conflicts(). The conflict may cease to
// exist as a side-effect of this call.
void resolve();
// Keep track of whether or not this conflict has a solution
// 1) a conflict may have a current solution. This gets invalidated
// whenever there is a change to a value that was referenced
// while identifying the solution.
//
// A current solution is indicated by a non-empty solution vector.
//
// 2) a conflict may not have a current solution. Again this gets
// invalidated whenever a referred value changes. There is a boolean
// to keep track of this.
//
// 3) a conflict may not have a current solution, but another run of
// the inference engine may find one.
bool has_known_solution() const;
bool has_no_solution() const;
const std::vector<std::pair<CdlValuable, CdlValue> >& get_solution() const;
const std::set<CdlValuable>& get_solution_references() const;
void clear_solution();
// Provide a text message "explaining" the conflict.
// This only makes sense for derived classes.
virtual std::string get_explanation() const = 0;
// Basic information access.
CdlNode get_node() const;
CdlProperty get_property() const;
bool is_structural() const;
// Enabling and disabling conflicts currently happens outside the
// context of any transaction.
// FIXME: these are not currently implemented. It would be necessary
// to store the information in the savefile, which requires an
// unambiguous way of identifying a conflict that is likely to
// survice package version changes.
void disable(std::string);
void enable();
bool is_enabled() const;
std::string get_disabled_reason() const;
bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlConflictBody(CdlTransaction, CdlNode, CdlProperty, bool /* structural */);
// The destructor gets accessed from inside the friend transaction class,
// either during a clear_conflict() or during a transaction commit.
virtual ~CdlConflictBody();
// All conflicts are associated with a node and a property.
// This information will be useful to derived classes'
// implementations of get_explanation()
CdlNode node;
CdlProperty property;
private:
// Attempt to resolve a conflict in a sub-transaction
// This is invoked from inside the transaction resolve code.
// There are additional exported interfaces inside and outside
// the transaction class.
virtual bool inner_resolve(CdlTransaction, int);
// Keep track of the transaction in which this conflict was created.
// The field is cleared at the end of a transaction.
CdlTransaction transaction;
// Usually the derived class will decide whether or not
// this conflict is structural in nature, but the data
// needs to be available at base constructor time so
// a virtual function is not appropriate.
bool structural;
// Solution support
bool no_solution;
std::vector<std::pair<CdlValuable, CdlValue> > solution;
std::set<CdlValuable> solution_references;
void update_solution_validity(CdlValuable);
// Users may disable a conflict. Usually they will have to
// supply a reason for this.
bool enabled;
std::string reason;
enum {
CdlConflictBody_Invalid = 0,
CdlConflictBody_Magic = 0x073e8853
} cdlconflictbody_cookie;
// Illegal operations. Conflicts always live on the heap.
CdlConflictBody();
CdlConflictBody(const CdlConflictBody&);
CdlConflictBody& operator=(const CdlConflictBody&);
};
// ----------------------------------------------------------------------------
// An unresolved conflict means that there is a reference in some
// property to an entity that is not yet in the current configuration.
// The class provides convenient access to the name of the unresolved
// entity.
class CdlConflict_UnresolvedBody : public CdlConflictBody {
friend class CdlTest;
public:
static void make(CdlTransaction, CdlNode, CdlProperty, std::string);
std::string get_target_name() const;
std::string get_explanation() const;
static bool test(CdlConflict);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
virtual ~CdlConflict_UnresolvedBody();
CdlConflict_UnresolvedBody(CdlTransaction, CdlNode, CdlProperty, std::string);
std::string target_name;
enum {
CdlConflict_UnresolvedBody_Invalid = 0,
CdlConflict_UnresolvedBody_Magic = 0x1b24bb8a
} cdlconflict_unresolvedbody_cookie;
CdlConflict_UnresolvedBody();
CdlConflict_UnresolvedBody(const CdlConflict_UnresolvedBody&);
CdlConflict_UnresolvedBody& operator=(const CdlConflict_UnresolvedBody&);
};
// ----------------------------------------------------------------------------
// An illegal value can be caused because of a number of properties:
// legal_values, check_proc, entry_proc, ... In the case of the latter
// the Tcl code should provide text explaining why the value is
// illegal.
class CdlConflict_IllegalValueBody : public CdlConflictBody {
friend class CdlTest;
public:
static void make(CdlTransaction, CdlNode, CdlProperty);
bool resolution_implemented() const;
std::string get_explanation() const;
void set_explanation(std::string);
static bool test(CdlConflict);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
virtual ~CdlConflict_IllegalValueBody();
bool inner_resolve(CdlTransaction, int);
CdlConflict_IllegalValueBody(CdlTransaction, CdlNode, CdlProperty);
std::string explanation;
enum {
CdlConflict_IllegalValueBody_Invalid = 0,
CdlConflict_IllegalValueBody_Magic = 0x4fb27ed1
} cdlconflict_illegalvaluebody_cookie;
CdlConflict_IllegalValueBody();
CdlConflict_IllegalValueBody(const CdlConflict_IllegalValueBody&);
CdlConflict_IllegalValueBody& operator=(const CdlConflict_IllegalValueBody&);
};
// ----------------------------------------------------------------------------
// There are times when expression evaluation will fail, e.g. because of
// a division by zero. The explanation is supplied by the evaluation code.
class CdlConflict_EvalExceptionBody : public CdlConflictBody {
friend class CdlTest;
public:
static void make(CdlTransaction, CdlNode, CdlProperty, std::string);
std::string get_explanation() const;
void set_explanation(std::string); // mainly for internal use
static bool test(CdlConflict);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
virtual ~CdlConflict_EvalExceptionBody();
CdlConflict_EvalExceptionBody(CdlTransaction, CdlNode, CdlProperty, std::string);
std::string explanation;
enum {
CdlConflict_EvalExceptionBody_Invalid = 0,
CdlConflict_EvalExceptionBody_Magic = 0x7e64bc41
} cdlconflict_evalexceptionbody_cookie;
};
// ----------------------------------------------------------------------------
// A goal expression evaluates to false. Producing sensible diagnostics
// depends on a detailed understanding of goal expressions, which will
// have to wait until the inference engine comes along.
class CdlConflict_RequiresBody : public CdlConflictBody {
friend class CdlTest;
public:
static void make(CdlTransaction, CdlNode, CdlProperty);
bool resolution_implemented() const;
std::string get_explanation() const;
static bool test(CdlConflict);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
virtual ~CdlConflict_RequiresBody();
bool inner_resolve(CdlTransaction, int);
CdlConflict_RequiresBody(CdlTransaction, CdlNode, CdlProperty);
enum {
CdlConflict_RequiresBody_Invalid = 0,
CdlConflict_RequiresBody_Magic = 0x78436331
} cdlconflict_requiresbody_cookie;
};
// ----------------------------------------------------------------------------
// There is an unusual problem in the configuration data somewhere.
// For example, a parent property can be resolved but the target is
// not a container. There is not a lot that the user can do about
// problems like this, apart from complaining to the component vendor,
// but the problem should not be ignored either.
class CdlConflict_DataBody : public CdlConflictBody {
friend class CdlTest;
public:
static void make(CdlTransaction, CdlNode, CdlProperty, std::string);
std::string get_explanation() const;
static bool test(CdlConflict);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
virtual ~CdlConflict_DataBody();
CdlConflict_DataBody(CdlTransaction, CdlNode, CdlProperty, std::string);
std::string message;
enum {
CdlConflict_DataBody_Invalid = 0,
CdlConflict_DataBody_Magic = 0x2cec7ad8
} cdlconflict_databody_cookie;
};
//}}}
//{{{ CdlProperty class and derived classes
//{{{ Description
// ---------------------------------------------------------------------------
// There are many different kinds of property. An alias property contains
// a simple string. A check_proc property contains a fragment of Tcl code
// which can be represented internally as a string, as bytecodes, or both.
// A requires property contains a goal expression. ...
//
// The implementation involves a base class CdlProperty and various
// derived classes such as CdlProperty_StringBody and
// CdlProperty_ExpressionBody.
//
// New CdlProperty objects get created only when reading in CDL scripts,
// while executing commands like alias and requires. These commands are
// implemented as C++ functions hooked into the TCL interpreter. The
// property arguments are available as an argc/argv pair. Each command
// will parse and validate the arguments and then invoke an appropriate
// constructor.
//}}}
//{{{ CdlPropertyId_xxx
// ----------------------------------------------------------------------------
// Properties are identified by strings rather than by an enum or anything
// like that. A string-based approach allows new properties to be added at
// any time without invalidating an existing enum, complicating switch()
// statements, etc. There are some performance issues but these are
// manageable.
//
// A disadvantage of using strings is that there is a problem with
// typos. Mistyping something like CdlPropertyId_Compile will generally
// result in a compile-time failure. Mistyping "Complie" will cause
// strange behaviour at run-time and is hard to track down.
//
// A compromise solution is to have #define'd string constants.
#define CdlPropertyId_ActiveIf "ActiveIf"
#define CdlPropertyId_BuildProc "BuildProc"
#define CdlPropertyId_Calculated "Calculated"
#define CdlPropertyId_CancelProc "CancelProc"
#define CdlPropertyId_CheckProc "CheckProc"
#define CdlPropertyId_Compile "Compile"
#define CdlPropertyId_ConfirmProc "ConfirmProc"
#define CdlPropertyId_DecorationProc "DecorationProc"
#define CdlPropertyId_DefaultValue "DefaultValue"
#define CdlPropertyId_Define "Define"
#define CdlPropertyId_DefineHeader "DefineHeader"
#define CdlPropertyId_DefineProc "DefineProc"
#define CdlPropertyId_Description "Description"
#define CdlPropertyId_Dialog "Dialog"
#define CdlPropertyId_Display "Display"
#define CdlPropertyId_DisplayProc "DisplayProc"
#define CdlPropertyId_Doc "Doc"
#define CdlPropertyId_EntryProc "EntryProc"
#define CdlPropertyId_Flavor "Flavor"
#define CdlPropertyId_DefineFormat "DefineFormat"
#define CdlPropertyId_Group "Group"
#define CdlPropertyId_Hardware "Hardware"
#define CdlPropertyId_IfDefine "IfDefine"
#define CdlPropertyId_Implements "Implements"
#define CdlPropertyId_IncludeDir "IncludeDir"
#define CdlPropertyId_IncludeFiles "IncludeFiles"
#define CdlPropertyId_InitProc "InitProc"
#define CdlPropertyId_InstallProc "InstallProc"
#define CdlPropertyId_LegalValues "LegalValues"
#define CdlPropertyId_Library "Library"
#define CdlPropertyId_LicenseProc "LicenseProc"
#define CdlPropertyId_Make "Make"
#define CdlPropertyId_Makefile "Makefile"
#define CdlPropertyId_MakeObject "MakeObject"
#define CdlPropertyId_NoDefine "NoDefine"
#define CdlPropertyId_Object "Object"
#define CdlPropertyId_Parent "Parent"
#define CdlPropertyId_Requires "Requires"
#define CdlPropertyId_Screen "Screen"
#define CdlPropertyId_Script "Script"
#define CdlPropertyId_UpdateProc "UpdateProc"
#define CdlPropertyId_Wizard "Wizard"
//}}}
//{{{ Base class
// ----------------------------------------------------------------------------
// The base class is never used directly. Instead the appropriate derived
// objects are instantiated and when appropriate it will be necessary to
// do a dynamic cast from a CdlProperty to e.g. a CdlProperty_String.
class CdlPropertyBody {
friend class CdlTest;
public:
// The destructor is public, to avoid possible problems with STL.
virtual ~CdlPropertyBody();
// These routines provide access to the basic data.
std::string get_property_name() const;
// Get hold of the arguments that were present in the original data.
int get_argc() const;
bool has_option(std::string) const;
std::string get_option(std::string) const;
const std::vector<std::string>& get_argv() const;
const std::vector<std::pair<std::string,std::string> >& get_options() const;
// Resolve any references, or generate/update appropriate conflict
// objects. The default implementation is a no-op because not all
// properties involve references.
virtual void update(CdlTransaction, CdlNode /* source */, CdlNode /* dest */, CdlUpdate);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
// The legal constructor can only get invoked from a derived class
// constructor. The first argument identifies the property, e.g.
// CdlPropertyId_Doc (which is just #define'd to the string
// "doc").
//
// The argc and argv fields provide access to the original
// data in the command that resulted in the property being
// constructed. Often but not always argv[0] will be the same as
// the property id. The argv information is stored mainly for
// diagnostics purposes, it may be removed in future to avoid
// wasting memory.
//
// The options field is the result of parsing options such
// as -library=libextras.a. It consists of a vector of
// <name/value> pairs, and is usually obtained via
// CdlParse::parse_options().
CdlPropertyBody(CdlNode, std::string, int argc, const char* argv[], std::vector<std::pair<std::string,std::string> >&);
private:
// This string indicates the command used to define this property,
// e.g. "doc" or "define_proc". It is provided to the constructor.
std::string name;
// All property data comes out of a file and gets rid via a
// Tcl interpreter. The raw file data is stored with the property,
// mainly for diagnostics purposes.
std::vector<std::string> argv;
std::vector<std::pair<std::string, std::string> > options;
// The usual set of illegal operations.
CdlPropertyBody();
CdlPropertyBody(const CdlPropertyBody&);
CdlPropertyBody& operator=(const CdlPropertyBody&);
enum {
CdlPropertyBody_Invalid = 0,
CdlPropertyBody_Magic = 0x60dd58f4
} cdlpropertybody_cookie;
};
//}}}
//{{{ CdlProperty_Minimal
// ----------------------------------------------------------------------------
// This class is used for properties that are simple flags, e.g. no_define.
// There should be no additional data associated with such properties.
class CdlProperty_MinimalBody : public CdlPropertyBody {
friend class CdlTest;
public:
static CdlProperty_Minimal make(CdlNode, std::string, int, const char*[], std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_MinimalBody( );
bool check_this( cyg_assert_class_zeal = cyg_quick ) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
typedef CdlPropertyBody inherited;
CdlProperty_MinimalBody(CdlNode, std::string, int, const char*[], std::vector<std::pair<std::string,std::string> >&);
enum {
CdlProperty_MinimalBody_Invalid = 0,
CdlProperty_MinimalBody_Magic = 0x25625b8c
} cdlproperty_minimalbody_cookie;
CdlProperty_MinimalBody();
CdlProperty_MinimalBody(const CdlProperty_MinimalBody&);
CdlProperty_MinimalBody& operator=(const CdlProperty_MinimalBody&);
};
//}}}
//{{{ CdlProperty_String
// ----------------------------------------------------------------------------
// A string property contains a single piece of additional data in the form
// of a string.
class CdlProperty_StringBody : public CdlPropertyBody {
friend class CdlTest;
public:
static CdlProperty_String make(CdlNode, std::string, std::string, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_StringBody();
std::string get_string(void) const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
typedef CdlPropertyBody inherited;
CdlProperty_StringBody(CdlNode, std::string /* id */, std::string /* data */, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
std::string data;
enum {
CdlProperty_StringBody_Invalid = 0,
CdlProperty_StringBody_Magic = 0x78d1ca94
} cdlproperty_stringbody_cookie;
// The only legal constructor supplies all the data.
CdlProperty_StringBody();
CdlProperty_StringBody(const CdlProperty_StringBody&);
CdlProperty_StringBody& operator=(const CdlProperty_StringBody&);
};
//}}}
//{{{ CdlProperty_TclCode
// ----------------------------------------------------------------------------
// A TclCode property is currently equivalent to a string property. In
// future this may change to allow the byte-compiled versions of the
// script to be stored.
//
// One of the properties, "screen" inside a cdl_wizard, also takes
// an integer. Rather than create yet another class, this is handled
// by a separate constructor.
class CdlProperty_TclCodeBody : public CdlPropertyBody {
friend class CdlTest;
public:
static CdlProperty_TclCode make(CdlNode, std::string, cdl_tcl_code, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
static CdlProperty_TclCode make(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_TclCodeBody();
cdl_int get_number(void) const;
const cdl_tcl_code& get_code(void) const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
typedef CdlPropertyBody inherited;
CdlProperty_TclCodeBody(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
cdl_int number;
cdl_tcl_code code;
enum {
CdlProperty_TclCodeBody_Invalid = 0,
CdlProperty_TclCodeBody_Magic = 0x7b14d4e5
} cdlproperty_tclcodebody_cookie;
CdlProperty_TclCodeBody();
CdlProperty_TclCodeBody(const CdlProperty_TclCodeBody&);
CdlProperty_TclCodeBody& operator=(const CdlProperty_TclCodeBody&);
};
//}}}
//{{{ CdlProperty_StringVector
// ----------------------------------------------------------------------------
// This is used for multiple constant strings, as opposed to a list
// expression which requires evaluation. One example is a list
// of aliases.
class CdlProperty_StringVectorBody : public CdlPropertyBody {
friend class CdlTest;
public:
static CdlProperty_StringVector make(CdlNode, std::string, const std::vector<std::string>&, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_StringVectorBody();
const std::vector<std::string>& get_strings() const;
std::string get_first_string() const;
unsigned int get_number_of_strings() const;
std::string get_string(unsigned int) const;
bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
typedef CdlPropertyBody inherited;
CdlProperty_StringVectorBody(CdlNode, std::string, const std::vector<std::string>&, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
std::vector<std::string> data;
enum {
CdlProperty_StringVectorBody_Invalid = 0,
CdlProperty_StringVectorBody_Magic = 0x4ed039f3
} cdlproperty_stringvectorbody_cookie;
CdlProperty_StringVectorBody();
CdlProperty_StringVectorBody(const CdlProperty_StringVectorBody&);
CdlProperty_StringVectorBody& operator=(const CdlProperty_StringVectorBody&);
};
//}}}
//{{{ CdlProperty_Reference
// ----------------------------------------------------------------------------
// This is used for properties such as wizard and dialog, where the data
// identifies some other entity in the system. The class is both a property
// and a reference object. Most of the desired functionality is provided by
// inheritance from CdlReference.
class CdlProperty_ReferenceBody : public CdlPropertyBody, public CdlReference {
friend class CdlTest;
public:
static CdlProperty_Reference make(CdlNode, std::string /* id */, std::string /* destination */,
CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_ReferenceBody();
void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
typedef CdlPropertyBody inherited_property;
typedef CdlReference inherited_reference;
CdlUpdateHandler update_handler;
CdlProperty_ReferenceBody(CdlNode, std::string /* id */, std::string /* destination */, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
enum {
CdlProperty_ReferenceBody_Invalid = 0,
CdlProperty_ReferenceBody_Magic = 0x78100339
} cdlproperty_referencebody_cookie;
CdlProperty_ReferenceBody();
CdlProperty_ReferenceBody(const CdlProperty_ReferenceBody&);
CdlProperty_ReferenceBody& operator=(const CdlProperty_Reference&);
};
//}}}
//{{{ CdlProperty_Expression
// ----------------------------------------------------------------------------
// An expression property simply inherits its functionality from the basic
// property class and from the expression class.
class CdlProperty_ExpressionBody : public CdlPropertyBody, public CdlExpressionBody {
friend class CdlTest;
public:
static CdlProperty_Expression make(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_ExpressionBody();
void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
typedef CdlPropertyBody inherited_property;
typedef CdlExpressionBody inherited_expression;
CdlProperty_ExpressionBody(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
CdlUpdateHandler update_handler;
enum {
CdlProperty_ExpressionBody_Invalid = 0,
CdlProperty_ExpressionBody_Magic = 0x05fb4056
} cdlproperty_expressionbody_cookie;
CdlProperty_ExpressionBody();
CdlProperty_ExpressionBody(const CdlProperty_ExpressionBody&);
CdlProperty_ExpressionBody& operator=(const CdlProperty_ExpressionBody&);
};
//}}}
//{{{ CdlProperty_ListExpression
// ----------------------------------------------------------------------------
// Similarly a list property simply inherits from property and from
// list expressions.
class CdlProperty_ListExpressionBody : public CdlPropertyBody, public CdlListExpressionBody {
friend class CdlTest;
public:
static CdlProperty_ListExpression make(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_ListExpressionBody();
void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
typedef CdlPropertyBody inherited_property;
typedef CdlListExpressionBody inherited_expression;
CdlProperty_ListExpressionBody(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
CdlUpdateHandler update_handler;
enum {
CdlProperty_ListExpressionBody_Invalid = 0,
CdlProperty_ListExpressionBody_Magic = 0x6b0136f5
} cdlproperty_listexpressionbody_cookie;
CdlProperty_ListExpressionBody();
CdlProperty_ListExpressionBody(const CdlProperty_ListExpressionBody&);
CdlProperty_ListExpressionBody& operator=(const CdlProperty_ListExpressionBody&);
};
//}}}
//{{{ CdlProperty_GoalExpression
// ----------------------------------------------------------------------------
// And a goal property inherits from property and from goal expressions.
class CdlProperty_GoalExpressionBody : public CdlPropertyBody, public CdlGoalExpressionBody {
friend class CdlTest;
public:
static CdlProperty_GoalExpression make(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
virtual ~CdlProperty_GoalExpressionBody();
void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
typedef CdlPropertyBody inherited_property;
typedef CdlGoalExpressionBody inherited_expression;
CdlProperty_GoalExpressionBody(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
std::vector<std::pair<std::string,std::string> >&);
CdlUpdateHandler update_handler;
enum {
CdlProperty_GoalExpressionBody_Invalid = 0,
CdlProperty_GoalExpressionBody_Magic = 0x08b2b31e
} cdlproperty_goalexpressionbody_cookie;
CdlProperty_GoalExpressionBody();
CdlProperty_GoalExpressionBody(const CdlProperty_GoalExpressionBody&);
CdlProperty_GoalExpressionBody& operator=(const CdlProperty_GoalExpressionBody&);
};
//}}}
//}}}
//{{{ CdlParse class
// ----------------------------------------------------------------------------
// This is another utility class for collecting together parsing-related
// functions.
//
// Note that this is only a utility class. When libcdl is used for parsing
// things not related to software configuration the new functionality
// does not have to reside inside the CdlParse class, but it may be
// possible to re-use some of the functionality in that class.
class CdlParse {
public:
// Utility routines.
static std::string get_tcl_cmd_name(std::string);
static std::string concatenate_argv(int, const char*[], int);
static int parse_options(CdlInterpreter, std::string /* diag_prefix */, char** /* options */,
int /* argc */, const char*[] /* argv */, int /* start_index */,
std::vector<std::pair<std::string,std::string> >& /* result */);
static std::string construct_diagnostic(CdlInterpreter, std::string /* classification */,
std::string /* sub-identifier */, std::string /* message */);
static void report_error(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
static void report_warning(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
static void clear_error_count(CdlInterpreter);
static int get_error_count(CdlInterpreter);
static void incr_error_count(CdlInterpreter, int=1);
static std::string get_expression_error_location(void);
// Support for Tcl's "unknown" command
static int unknown_command(CdlInterpreter, int, const char*[]);
// Property-related utilities
static void report_property_parse_error(CdlInterpreter, std::string, std::string);
static void report_property_parse_error(CdlInterpreter, CdlProperty, std::string);
static void report_property_parse_warning(CdlInterpreter, std::string, std::string);
static void report_property_parse_warning(CdlInterpreter, CdlProperty, std::string);
// Utility parsing routines
static int parse_minimal_property(CdlInterpreter, int, const char*[], std::string,
char**, void (*)(CdlInterpreter, CdlProperty_Minimal));
static int parse_string_property(CdlInterpreter, int, const char*[], std::string,
char**, void (*)(CdlInterpreter, CdlProperty_String));
static int parse_tclcode_property(CdlInterpreter, int, const char*[], std::string,
char**, void (*)(CdlInterpreter, CdlProperty_TclCode));
static int parse_stringvector_property(CdlInterpreter, int, const char*[], std::string,
char**, void (*)(CdlInterpreter, CdlProperty_StringVector),
bool /* allow_empty */ = false);
static int parse_reference_property(CdlInterpreter, int, const char*[], std::string,
char**, void (*)(CdlInterpreter, CdlProperty_Reference),
bool /* allow_empty */,
CdlUpdateHandler);
static int parse_expression_property(CdlInterpreter, int, const char*[], std::string,
char **, void (*)(CdlInterpreter, CdlProperty_Expression),
CdlUpdateHandler);
static int parse_listexpression_property(CdlInterpreter, int, const char*[], std::string,
char **, void (*)(CdlInterpreter, CdlProperty_ListExpression),
CdlUpdateHandler);
static int parse_goalexpression_property(CdlInterpreter, int, const char*[], std::string,
char **, void (*)(CdlInterpreter, CdlProperty_GoalExpression),
CdlUpdateHandler);
};
//}}}
//{{{ CdlNode
// ----------------------------------------------------------------------------
// A node object has a name and lives in a hierarchy. Each node keeps
// track of the toplevel and owner. The memory overheads are
// relatively small compared with the performance gains when such
// information is needed.
//
// A node object also has a vector of properties, and can be referred to
// by properties in other nodes. Some of the properties may result in
// conflicts.
class CdlNodeBody {
friend class CdlTest;
// Adding and removing nodes from the hierarchy is done
// by CdlToplevel members.
friend class CdlToplevelBody;
// CdlLoadable must be able to access the destructor
friend class CdlLoadableBody;
// It is intended that CdlProperties will also add and remove themselves
friend class CdlPropertyBody;
// CdlReference bind and unbind operations need access to
// the referrers vector. So does CdlTransaction::commit()
friend class CdlReference;
friend class CdlTransactionBody;
public:
// Basic information.
std::string get_name() const;
CdlContainer get_parent() const;
CdlLoadable get_owner() const;
CdlToplevel get_toplevel() const;
// Propagation support. Some updates such as active/inactive changes
// get applied to nodes as well as to properties. Note that because
// of multiple inheritance this virtual call can get confusing.
virtual void update(CdlTransaction, CdlUpdate);
// Is this node active or not? The is_active() call refers
// to the global state, things may be different inside a
// transaction.
bool is_active() const;
bool is_active(CdlTransaction transaction);
// Generally nodes become active when the parent becomes
// active and enabled. Some derived classes may impose
// additional restrictions, for example because of
// active_if constraints. This routine can be used
// to check whether or not a node should become active.
virtual bool test_active(CdlTransaction);
// Provide access to the various properties. Currently all this
// information is publicly available.
const std::vector<CdlProperty>& get_properties() const;
CdlProperty get_property(std::string) const;
void get_properties(std::string, std::vector<CdlProperty>&) const;
std::vector<CdlProperty> get_properties(std::string) const;
bool has_property(std::string) const;
int count_properties(std::string) const;
// Provide access to the various global conflicts. More
// commonly conflicts are accessed on a per-transaction basis.
void get_conflicts(std::vector<CdlConflict>&) const;
void get_conflicts(bool (*)(CdlConflict), std::vector<CdlConflict>&) const;
void get_structural_conflicts(std::vector<CdlConflict>&) const;
void get_structural_conflicts(bool (*)(CdlConflict), std::vector<CdlConflict>&) const;
// Provide access to all the referrers. This may not get used very
// much outside the library itself.
const std::vector<CdlReferrer>& get_referrers() const;
// Add property parsers and validation code appropriate for a
// node. Currently this is a no-op, there are no properties
// associated with every node, but this may change in future e.g.
// for diagnostics purposes.
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
// Persistence support. The final classes such as cdl_option
// should provide implementations of these functions. The
// base function takes care of data that was present in an
// original save file but which was not recognised.
//
// Configuration save files are Tcl scripts, so it seems
// appropriate to handle the I/O via the Tcl library and
// to have a TCL interpreter available.
virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
bool has_additional_savefile_information() const;
// Mainly for diagnostics code, what is the actual name for this
// type of CDL object? This should be in terms of CDL data, e.g.
// "package" or "component", rather than in implementation terms
// such as "CdlPackageBody".
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
// CdlNodeBodies are only instantiated by derived classes.
// They must always have a name. They need not be placed
// in the hierarchy immediately, that can wait until
// later.
CdlNodeBody(std::string);
// A dummy constructor is needed because of the virtual
// inheritance.
CdlNodeBody();
// Nodes cannot be destroyed directly by application code,
// only by higher-level library functions such as unload_package()
virtual ~CdlNodeBody();
// Updating the name is rarely required, but is useful for savefiles.
void set_name(std::string);
// Is the node currently active? This applies to the global state
// only, not per-transaction state. Some derived classes may want
// to override the default value
bool active;
private:
// The basic data. The name is known during construction.
// The other three fields get updated by e.g. CdlToplevel::add_node();
std::string name;
CdlContainer parent;
CdlLoadable owner;
CdlToplevel toplevel;
// This is used by remove_node_from_toplevel()/add_node_to_toplevel()
// to allow the latter to exactly reverse the former
int remove_node_container_position;
// Properties normally only get added during the parsing process,
// and only get removed when the object itself is destroyed.
// A vector is the obvious implementation.
std::vector<CdlProperty> properties;
// Currently a vector of referrers is used. This vector is subject
// to change when packages get loaded and unloaded, possibly a
// list would be better.
std::vector<CdlReferrer> referrers;
// Savefiles may contain information that is not recognised by the
// current library, especially because of savefile hooks which
// allow e.g. the configuration tool to store its own information
// in save files. This information must not be lost, even if you are
// e.g. mixing command line and GUI tools. This vector holds
// the savefile information so that it can be put in the next
// savefile.
std::vector<std::string> unsupported_savefile_strings;
enum {
CdlNodeBody_Invalid = 0,
CdlNodeBody_Magic = 0x309595b5
} cdlnodebody_cookie;
// Illegal operations
CdlNodeBody(const CdlNodeBody&);
CdlNodeBody& operator=(const CdlNodeBody&);
};
//}}}
//{{{ CdlContainer
// ----------------------------------------------------------------------------
// A container is a node that can contain other nodes.
class CdlContainerBody : virtual public CdlNodeBody {
friend class Cdltest;
// Allow CdlNode::check_this() access to the internals
friend class CdlNodeBody;
// Adding a node to the hierarchy is done by a CdlToplevel member.
// Ditto for removing.
friend class CdlToplevelBody;
// Deleting a container can happen inside CdlToplevel and CdlLoadable
friend class CdlLoadableBody;
public:
const std::vector<CdlNode>& get_contents() const;
bool contains(CdlConstNode, bool /* recurse */ = false) const;
bool contains(const std::string, bool /* recurse */ = false) const;
CdlNode find_node(const std::string, bool /* recurse */ = false) const;
// Propagation support. Some updates such as active/inactive changes
// get applied to nodes as well as to properties.
virtual void update(CdlTransaction, CdlUpdate);
// Persistence support.
virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
// Containers cannot be destroyed explicitly, only via higher-level
// code such as unload_package();
virtual ~CdlContainerBody();
CdlContainerBody();
// Special constructor needed for internal use.
CdlContainerBody(std::string);
// The CdlToplevel class needs access to its own contents.
std::vector<CdlNode> contents;
private:
enum {
CdlContainerBody_Invalid = 0,
CdlContainerBody_Magic = 0x543c5f1d
} cdlcontainerbody_cookie;
// Illegal operations
CdlContainerBody(const CdlContainerBody&);
CdlContainerBody& operator=(const CdlContainerBody&);
};
//}}}
//{{{ CdlLoadable
// ----------------------------------------------------------------------------
// A loadable object is a container that gets loaded or unloaded
// atomically from a toplevel. The key difference is that a loadable
// keeps track of all nodes that were loaded as part of this
// operation, thus allowing unload operations to happen safely even if
// nodes get re-parented all over the hierarchy. In addition, there is
// a slave interpreter associated with every loadable.
class CdlLoadableBody : virtual public CdlContainerBody {
friend class CdlTest;
// Allow CdlNode::check_this() access to the internals
friend class CdlNodeBody;
// Adding nodes to the hierarchy is done by a toplevel member
friend class CdlToplevelBody;
public:
virtual ~CdlLoadableBody();
const std::vector<CdlNode>& get_owned() const;
bool owns(CdlConstNode) const;
CdlInterpreter get_interpreter() const;
std::string get_directory() const;
// Some properties such as doc and compile reference filenames.
// A search facility is useful.
virtual std::string find_relative_file(std::string /* filename */, std::string /* directory */ = "") const;
virtual std::string find_absolute_file(std::string, std::string, bool /* allow_urls */ = false) const;
virtual bool has_subdirectory(std::string) const;
// These support load/unload operations inside transactions
// They are static members because some of them will want
// to delete the loadable.
static void transaction_commit_load(CdlTransaction, CdlLoadable);
static void transaction_cancel_load(CdlTransaction, CdlLoadable);
static void transaction_commit_unload(CdlTransaction, CdlLoadable);
static void transaction_cancel_unload(CdlTransaction, CdlLoadable);
// Binding and unbinding of properties. This involves processing
// the various properties, calculating default values, etc.
void bind(CdlTransaction);
void unbind(CdlTransaction);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlLoadableBody(CdlToplevel, std::string /* directory */);
// Needed by derived classes, but not actually used.
CdlLoadableBody();
private:
std::vector<CdlNode> owned;
CdlInterpreter interp;
std::string directory;
// Used by add/remove_node_from_toplevel()
int remove_node_loadables_position;
enum {
CdlLoadableBody_Invalid = 0,
CdlLoadableBody_Magic = 0x488d6127
} cdlloadablebody_cookie;
// Invalid operations
CdlLoadableBody(const CdlLoadableBody&);
CdlLoadableBody& operator=(const CdlLoadableBody&);
};
//}}}
//{{{ CdlToplevel
// ----------------------------------------------------------------------------
// Toplevels are containers that live at the top of a hierarchy
// (surprise surprise). This means that they do not have a parent.
// In addition a toplevel object keeps track of all the names
// used, guaranteeing uniqueness and providing a quick lookup
// facility.
//
// Every container is also a node, so every toplevel is a node.
// Inheritance from CdlNode may seem wrong. However it achieves
// consistency, everything in the hierarchy including the toplevel
// is a node. The main disadvantage is that every toplevel now
// needs a name.
class CdlToplevelBody : virtual public CdlContainerBody {
friend class CdlTest;
// Allow CdlNode::check_this() access to the internals
friend class CdlNodeBody;
// The CdlTransaction class needs direct access to the lists
// of conflicts.
friend class CdlTransactionBody;
public:
virtual ~CdlToplevelBody();
// Updating the hierarchy. This happens a node at a time. Adding a
// node involves updating the name->node map in the toplevel,
// setting the node's parent/owner/toplevel fields, and updating
// the parent and owner containers. The owner may be 0 for special
// nodes such as the orphans container. The parent must be known,
// although it may change later on during a change_parent() call.
//
// Removing a node is more complicated, and involves a two-stage
// process. First the node is removed from the toplevel, thus
// eliminating the name->node mapping. The owner and parent fields
// are preserved at this stage (except for the loadable itself),
// and the operation may be undone if the relevant transaction
// gets cancelled. If the transaction gets committed then the
// second remove operation handles the owner and parent fields,
// just prior to the node being deleted. For convenience there
// are also per-loadable variants for some of these.
//
// change_parent() is used to support parent-properties.
// A container of 0 indicates an orphan, i.e. a parent
// property that did not or does not correspond to a
// current container.
//
// There is also a clean-up call. This gets used for interfaces
// which may alternate between belonging to a loadable and
// being auto-created.
void add_node(CdlLoadable, CdlContainer, CdlNode);
void add_node_to_toplevel(CdlNode);
void remove_node_from_toplevel(CdlNode);
static void remove_node(CdlLoadable, CdlContainer, CdlNode);
void add_loadable_to_toplevel(CdlLoadable);
void remove_loadable_from_toplevel(CdlLoadable);
void change_parent(CdlLoadable, CdlContainer /* current */, CdlContainer /* new */, CdlNode, int /* pos */ = -1);
void cleanup_orphans();
// Toplevels keep track of all the loadables, in addition to
// inheriting tree behaviour from CdlContainer. This is convenient
// for some operations like determining build information
// which must operate on a per-loadable basis.
const std::vector<CdlLoadable>& get_loadables() const;
// Name uniqueness is guaranteed. It is convenient to have an STL
// map as a lookup service.
CdlNode lookup(const std::string) const;
// There are two conflict lists associated with each toplevel. One
// is for "structural" conflicts, ones that can only be resolved
// by a fairly major change such as loading another package: a
// typical example is an unresolved parent reference. The other is
// for conflicts that can probably be resolved simply by changing
// some values. Both sets of conflicts are held as a simple list.
//
// The active vs. inactive state of a CDL entity affects the
// location of structural vs. non-structural conflicts. If an
// entity becomes inactive then structural conflicts are not
// affected, but non-structural conflicts are removed from the
// global list. If an entity's "requires" expression is not
// satisfied but the entity is inactive anyway then this is
// harmless.
const std::list<CdlConflict>& get_all_conflicts() const;
const std::list<CdlConflict>& get_all_structural_conflicts() const;
// Try to resolve some or all conflicts. Typically a new transaction
// will be created for this.
void resolve_conflicts(const std::vector<CdlConflict>&);
void resolve_all_conflicts();
// Toplevels can have descriptions provided by the user. This is
// particularly important for pre-defined templates, target
// board descriptions, etc. where the user would like some
// extra information about the template before loading it in.
// The default value is an empty string.
std::string get_description() const;
void set_description(std::string);
// Each toplevel must have an associated master Tcl interpreter.
CdlInterpreter get_interpreter() const;
// Each toplevel should also have an associated directory for
// the component repository. It is not required that all loadables
// are relative to this, but that is the default behaviour.
std::string get_directory() const;
// Each toplevel may have a single active main transaction.
// For now there is no support for concurrent transactions
// operating on a single toplevel (although nested transactions
// are allowed)
CdlTransaction get_active_transaction() const;
// Build and define operations are available for all toplevels,
// even if they are not always applicable
void get_build_info(CdlBuildInfo&);
void get_all_build_info(CdlBuildInfo&);
void generate_config_headers(std::string);
void get_config_headers(std::vector<std::string>&);
void generate_build_tree(std::string, std::string = "");
// Values can be stored in limbo. This is useful when unloading
// and reloading packages, e.g. when changing a version the
// current settings can be preserved as much as possible.
void set_limbo_value(CdlValuable);
bool has_limbo_value(std::string) const;
CdlValue get_limbo_value(std::string) const;
CdlValue get_and_remove_limbo_value(std::string);
void clear_limbo();
// Persistence support. These are commented in the source code.
void initialize_savefile_support();
static bool savefile_support_initialized();
void add_savefile_command(std::string, CdlSaveCallback, CdlInterpreterCommand);
void add_savefile_subcommand(std::string, std::string, CdlSaveCallback, CdlInterpreterCommand);
void get_savefile_commands(std::vector<CdlInterpreterCommandEntry>&);
void get_savefile_subcommands(std::string, std::vector<CdlInterpreterCommandEntry>&);
void save_command_details(CdlInterpreter, Tcl_Channel, int, bool);
static int savefile_handle_command(CdlInterpreter, int, const char*[]);
static int savefile_handle_unsupported(CdlInterpreter, int, const char*[]);
static int savefile_handle_unknown(CdlInterpreter, int, const char*[]);
void save_unsupported_commands(CdlInterpreter, Tcl_Channel, int, bool);
static cdl_int get_library_savefile_version();
static int savefile_handle_version(CdlInterpreter, int, const char*[]);
static cdl_int get_savefile_version(CdlInterpreter);
void save_conflicts(CdlInterpreter, Tcl_Channel, int, bool);
static void save_separator(CdlInterpreter, Tcl_Channel, std::string, bool);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlToplevelBody(CdlInterpreter, std::string);
private:
std::map<std::string,CdlNode> lookup_table;
std::vector<CdlLoadable> loadables;
std::map<std::string,CdlValue> limbo;
CdlInterpreter interp;
CdlContainer orphans;
std::string description;
std::string directory;
std::list<CdlConflict> conflicts;
std::list<CdlConflict> structural_conflicts;
// The savefile support corresponding to this application.
static cdl_int savefile_version;
static bool savefile_commands_initialized;
static std::vector<CdlSavefileCommand> savefile_commands;
static std::map<std::string,std::vector<CdlSavefileCommand> > savefile_subcommands;
// Per-toplevel support. A savefile may contain unrecognised
// commands at the toplevel of a file, as well as unrecognised
// commands in e.g. the body of a cdl_configuration command.
// The latter is handled via the CdlNode base class.
std::vector<std::string> unsupported_savefile_toplevel_strings;
std::vector<std::string> unsupported_savefile_commands;
std::map<std::string, std::vector<std::string> > unsupported_savefile_subcommands;
// Keep track of the current active transaction for this toplevel (if any)
CdlTransaction transaction;
enum {
CdlToplevelBody_Invalid = 0,
CdlToplevelBody_Magic = 0x0834666e
} cdltoplevelbody_cookie;
// Invalid operations
CdlToplevelBody(const CdlToplevelBody&);
CdlToplevelBody& operator=(const CdlToplevelBody&);
};
//}}}
//{{{ CdlUserVisible
// ----------------------------------------------------------------------------
// A user-visible object is likely to have properties such as display,
// description and doc. Many user-visible objects will have values but
// not all, for example custom dialogs are likely to have a doc
// property but they do not have a value.
class CdlUserVisibleBody : virtual public CdlNodeBody {
friend class CdlTest;
public:
virtual ~CdlUserVisibleBody();
std::string get_display() const;
std::string get_description() const;
std::string get_doc() const;
// NOTE: this will only work for absolute doc strings or for doc
// strings that are relative to the package.
std::string get_doc_url() const;
// Add property parsers and validation code appropriate for a
// user-visible object such as doc and description
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_description(CdlInterpreter, int, const char*[]);
static int parse_display(CdlInterpreter, int, const char*[]);
static int parse_doc(CdlInterpreter, int, const char*[]);
// Persistence support. The save code simply outputs some comments
// corresponding to the display, doc and description properties.
virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlUserVisibleBody();
private:
enum {
CdlUserVisibleBody_Invalid = 0,
CdlUserVisibleBody_Magic = 0x13bbc817
} cdluservisiblebody_cookie;
// Illegal operations
CdlUserVisibleBody(const CdlUserVisibleBody&);
CdlUserVisibleBody& operator=(const CdlUserVisibleBody&);
};
//}}}
//{{{ CdlParentable
// ----------------------------------------------------------------------------
// A parentable object may have the parent property, redefining its
// position in the hierarchy.
class CdlParentableBody : virtual public CdlNodeBody {
friend class CdlTest;
public:
virtual ~CdlParentableBody();
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_parent(CdlInterpreter, int, const char*[]);
static void update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlParentableBody();
private:
// Unloads may be cancelled. To restore the previous state exactly
// it is necessary to keep track of the old position.
int change_parent_save_position;
enum {
CdlParentableBody_Invalid = 0,
CdlParentableBody_Magic = 0x40c6a077
} cdlparentablebody_cookie;
// Illegal operations
CdlParentableBody(const CdlParentableBody&);
CdlParentableBody& operator=(const CdlParentableBody&);
};
//}}}
//{{{ CdlValuable
// ----------------------------------------------------------------------------
// A valuable body has a value. Many valuables can be modified but not all.
// Some properties make a valuable object read-only. In future there is
// likely to be support for locked values as well. There is a member function
// to check whether or not a valuable object is modifiable.
//
// Relevant properties for a valuable object are:
//
// 1) flavor - readily available via CdlValue::get_flavor()
// 2) default_value - an expression
// 3) legal_values - a list expression
// 4) entry_proc - for validation purposes, in addition to legal_values
// 5) check_proc - ditto
// 6) active_if - goal expression
// 7) requires - goal expression
// 8) dialog - a custom dialog for editing this value
// 9) calculated - non-modifiable
// 10) implements - for interfaces
//
// A CdlValuable does not inherit directly from CdlValue, since it should
// not be possible to modify a Valuable directly. Instead it contains a
// CdlValue member, and provides essentially the same functions as
// a CdlValue.
class CdlValuableBody : virtual public CdlNodeBody {
friend class CdlTest;
// Transaction commit operations require direct access to the CdlValue
friend class CdlTransactionBody;
private:
CdlValue value;
public:
virtual ~CdlValuableBody();
// Accessing the current value. There are variants for the global state
// and for per-transaction operations.
const CdlValue& get_whole_value() const;
CdlValueFlavor get_flavor() const;
CdlValueFlavor get_flavor(CdlTransaction transaction) const
{ // The transaction is irrelevant, it cannot change the flavor
return this->get_flavor();
}
CdlValueSource get_source() const;
bool has_source( CdlValueSource) const;
bool is_enabled( CdlValueSource = CdlValueSource_Current) const;
std::string get_value( CdlValueSource = CdlValueSource_Current) const;
bool has_integer_value( CdlValueSource = CdlValueSource_Current) const;
cdl_int get_integer_value( CdlValueSource = CdlValueSource_Current) const;
bool has_double_value( CdlValueSource = CdlValueSource_Current) const;
double get_double_value( CdlValueSource = CdlValueSource_Current) const;
CdlSimpleValue get_simple_value( CdlValueSource = CdlValueSource_Current) const;
CdlValueSource get_source(CdlTransaction) const;
bool has_source( CdlTransaction, CdlValueSource) const;
bool is_enabled( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
std::string get_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
bool has_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
cdl_int get_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
bool has_double_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
double get_double_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
CdlSimpleValue get_simple_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
// -----------------------------------------------------------------
// Modify access. There are two variants of all the functions:
//
// 1) no transaction argument. A transaction will be created,
// committed, and destroyed for the change in question.
//
// 2) a transaction argument. The existing transaction will be
// updated but not committed. This allows multiple changes
// to be grouped together.
//
// There are only a handful of exported functions, but lots
// of inline variants.
void set_source(CdlValueSource);
void invalidate_source(CdlValueSource);
void set_enabled(bool, CdlValueSource);
void set_value(CdlSimpleValue&, CdlValueSource);
void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
void set(CdlSimpleValue&, CdlValueSource);
void set_source(CdlTransaction, CdlValueSource);
void invalidate_source(CdlTransaction, CdlValueSource);
void set_enabled(CdlTransaction, bool, CdlValueSource);
void set_value(CdlTransaction, CdlSimpleValue&, CdlValueSource);
void set_enabled_and_value(CdlTransaction, bool, CdlSimpleValue&, CdlValueSource);
void set(CdlTransaction, CdlSimpleValue&, CdlValueSource);
void set(CdlTransaction, const CdlValue&);
void enable(CdlValueSource source)
{
set_enabled(true, source);
}
void disable(CdlValueSource source)
{
set_enabled(false, source);
}
void set_value(std::string data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(val, source);
}
void set_integer_value(cdl_int data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(val, source);
}
void set_double_value(double data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(val, source);
}
void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(enabled, val, source);
}
void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(enabled, val, source);
}
void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(enabled, val, source);
}
void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
{
set_enabled_and_value(true, val, source);
}
void enable_and_set_value(std::string data, CdlValueSource source)
{
set_enabled_and_value(true, data, source);
}
void enable_and_set_value(cdl_int data, CdlValueSource source)
{
set_enabled_and_value(true, data, source);
}
void enable_and_set_value(double data, CdlValueSource source)
{
set_enabled_and_value(true, data, source);
}
void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
{
set_enabled_and_value(false, val, source);
}
void disable_and_set_value(std::string data, CdlValueSource source)
{
set_enabled_and_value(false, data, source);
}
void disable_and_set_value(cdl_int data, CdlValueSource source)
{
set_enabled_and_value(false, data, source);
}
void disable_and_set_value(double data, CdlValueSource source)
{
set_enabled_and_value(false, data, source);
}
void enable(CdlTransaction transaction, CdlValueSource source)
{
set_enabled(transaction, true, source);
}
void disable(CdlTransaction transaction, CdlValueSource source)
{
set_enabled(transaction, false, source);
}
void set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(transaction, val, source);
}
void set_integer_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(transaction, val, source);
}
void set_double_value(CdlTransaction transaction, double data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_value(transaction, val, source);
}
void set_enabled_and_value(CdlTransaction transaction, bool enabled, std::string data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(transaction, enabled, val, source);
}
void set_enabled_and_value(CdlTransaction transaction, bool enabled, cdl_int data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(transaction, enabled, val, source);
}
void set_enabled_and_value(CdlTransaction transaction, bool enabled, double data, CdlValueSource source)
{
CdlSimpleValue val(data);
set_enabled_and_value(transaction, enabled, val, source);
}
void enable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
{
set_enabled_and_value(transaction, true, val, source);
}
void enable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
{
set_enabled_and_value(transaction, true, data, source);
}
void enable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
{
set_enabled_and_value(transaction, true, data, source);
}
void enable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
{
set_enabled_and_value(transaction, true, data, source);
}
void disable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
{
set_enabled_and_value(transaction, false, val, source);
}
void disable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
{
set_enabled_and_value(transaction, false, data, source);
}
void disable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
{
set_enabled_and_value(transaction, false, data, source);
}
void disable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
{
set_enabled_and_value(transaction, false, data, source);
}
// -----------------------------------------------------------------
virtual bool is_modifiable() const;
void get_widget_hint(CdlWidgetHint&);
// -----------------------------------------------------------------
// Propagation support. If a valuable becomes active or inactive
// because e.g. its parent is disabled then this may affect
// requires conflicts etc.
virtual void update(CdlTransaction, CdlUpdate);
virtual bool test_active(CdlTransaction);
// -----------------------------------------------------------------
// Property-related stuff.
bool has_calculated_expression() const;
bool has_default_value_expression() const;
bool has_legal_values() const;
bool has_entry_proc() const;
bool has_check_proc() const;
bool has_active_if_conditions() const;
bool has_requires_goals() const;
bool has_dialog() const;
bool has_wizard() const;
CdlProperty_Expression get_calculated_expression() const;
CdlProperty_Expression get_default_value_expression() const;
CdlProperty_ListExpression get_legal_values() const;
cdl_tcl_code get_entry_proc() const;
cdl_tcl_code get_check_proc() const;
void get_active_if_conditions(std::vector<CdlProperty_GoalExpression>&) const;
void get_requires_goals(std::vector<CdlProperty_GoalExpression>&) const;
CdlDialog get_dialog() const;
CdlWizard get_wizard() const;
void get_implemented_interfaces(std::vector<CdlInterface>&) const;
// Add property parsers and validation code appropriate for a
// valuable object such as default_value and legal_values
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_active_if(CdlInterpreter, int, const char*[]);
static void active_if_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_calculated(CdlInterpreter, int, const char*[]);
static void calculated_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_check_proc(CdlInterpreter, int, const char*[]);
static int parse_default_value(CdlInterpreter, int, const char*[]);
static void default_value_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_dialog(CdlInterpreter, int, const char*[]);
static void dialog_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_entry_proc(CdlInterpreter, int, const char*[]);
static int parse_flavor(CdlInterpreter, int, const char*[]);
static int parse_group(CdlInterpreter, int, const char*[]);
static int parse_implements(CdlInterpreter, int, const char*[]);
static void implements_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_legal_values(CdlInterpreter, int, const char*[]);
static void legal_values_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_requires(CdlInterpreter, int, const char*[]);
static void requires_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
static int parse_wizard(CdlInterpreter, int, const char*[]);
static void wizard_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
// Persistence suppot
void save(CdlInterpreter, Tcl_Channel, int, bool /* modifiable */, bool /* minimal */);
bool value_savefile_entry_needed() const;
static void initialize_savefile_support(CdlToplevel, std::string);
static int savefile_value_source_command(CdlInterpreter, int, const char*[]);
static int savefile_user_value_command(CdlInterpreter, int, const char*[]);
static int savefile_wizard_value_command(CdlInterpreter, int, const char*[]);
static int savefile_inferred_value_command(CdlInterpreter, int, const char*[]);
static int savefile_xxx_value_command(CdlInterpreter, int, const char*[], CdlValueSource);
// Make sure that the current value is legal. This gets called automatically
// by all the members that modify values. It has to be a virtual function
// since some derived classes, e.g. hardware-related valuables, may impose
// constraints over and above legal_values etc.
virtual void check_value(CdlTransaction);
// Similarly check the requires properties
void check_requires(CdlTransaction, CdlProperty_GoalExpression);
void check_requires(CdlTransaction);
// Enabling or disabling a valuable may affect the active state of children
void check_children_active(CdlTransaction);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlValuableBody(CdlValueFlavor = CdlValueFlavor_Bool);
private:
enum {
CdlValuableBody_Invalid = 0,
CdlValuableBody_Magic = 0x2b2acc03
} cdlvaluablebody_cookie;
// Illegal operations
CdlValuableBody(const CdlValuableBody&);
CdlValuableBody& operator=(const CdlValuableBody&);
};
//}}}
//{{{ CdlTransaction etc.
//{{{ Description
// ----------------------------------------------------------------------------
// Transactions. These are used for all changes to a configuration. In some
// cases a transaction is implicit:
//
// valuable->set_value(...)
//
// The actual implementation of this is:
//
// valuable->set_value(...)
// transact = CdlTransactionBody::make(valuable->get_toplevel())
// valuable->set_value(transact, ...)
// <complicated bits>
// transact->commit()
// delete transact
//
// Alternatively the use of transactions may be explicit. For implicit
// uses the library will invoke an inference callback at the
// appropriate time. For explicit transactions this is not necessary.
//
// The commit() operation invokes a transaction callback which should
// not be confused with the inference callback. The former is intended
// for display updates, it specifies everything that has changed
// during the transaction. The latter is used for reporting new
// conflicts to the user, suggesting fixes, etc.
//
// A whole bunch of information is associated with a transaction,
// including: all value changes, details of new conflicts, and details
// of existing conflicts that have gone away. The commit operation
// takes care of updating the toplevel. Until the commit happens
// the toplevel itself remains unchanged. It is also possible to cancel
// a transaction.
//
// An important concept related to transactions is propagation.
// Changing a value may have various effects, for example it may
// change the result of a legal_values list expression, resulting in a
// conflict object having to be created or destroyed. Changing one
// value may result in other value changes, e.g. because of a
// default_value property. All this is "propagation", and may
// happen multiple times within a single transaction.
//
// Transaction objects are also used during load or unload operations,
// but those are a little bit special. In particular it is not possible
// to cancel such a transaction, there will have been updates to the
// toplevel. Using a transaction is convenient because there is a
// need for propagation.
//
// Currently a transaction should be deleted immediately after a
// commit or cancel. This may change in future, in that transaction
// objects can be used to hold undo information.
//
//
// The other big concept related to transactions is inference.
// Changing a value may result in one or more new conflicts being
// created. In some cases the library can figure out for itself how to
// resolve these conflicts, using an inference engine. There are
// parameters to control the operation of the inference engine,
// including whether it runs at all, what changes it is allowed
// to make automatically (usually default and inferred values can
// be updated, but not wizard or user values), and how much
// recursion will happen.
//
// Assuming a default setup in a GUI environment, a typical
// sequence of events would be:
//
// valuable->set_value(...)
// transact = CdlTransactionBody::make(valuable->get_toplevel())
// valuable->set_value(transact, ...)
// transact->set_whole_value(valuable, ...)
// transact->propagate()
// while (!finished)
// transact->resolve()
// <inference>
// invoke inference callback
// transact->apply_solution() (1 or more times)
// transact->set_whole_value(valuable, ...) (1 or more times)
// transact->propagate()
// transact->commit() | transact->cancel()
// delete transact
//
// Note that the propagation steps have to be invoked explicitly,
// allowing multiple changes to be processed in one go. There is
// a utility function which combines the functionality from
// the first propagate() call up to but not including the
// transaction delete operator.
//
//
// The inference engine itself is a complicated beast. There are
// a number of interfaces, but at the end of the day it ends up
// creating a sub-transaction and trying to resolve a single
// conflict in that sub-transaction. The conflict may belong to
// the current transaction or it may be global.
//
// <inference>
// for each conflict of interest
// make sure that there is not already a valid solution
// check that the inference engine can handle it
// create a sub-transaction, associated with the conflict
// apply the conflict resolution code
// if the solution is ok
// install it
// else if the solution might e.g. overwrite a user value
// keep it, the user can decide during the inference callback
//
// The conflict resolution typically works by attempting to change
// one or more values in the sub-transaction, propagating them,
// and seeing what new conflicts get created. If no new conflicts
// get created and one or more existing conflicts go away, groovy.
// Otherwise recursion can be used to try to resolve the new
// conflicts, or other strategies can be explored.
//
// NOTE: what is really necessary is some way of keeping track of the
// "best" solution to date, and allow exploration of alternatives.
// Or possibly keep track of all solutions. That has to be left to
// a future version.
//}}}
//{{{ CdlTransactionCommitCancelOp
// ----------------------------------------------------------------------------
// The CdlTransaction class has built-in knowledge of how to handle values,
// active state, and a few things like that. However there are also more
// complicated operations such as loading and unloading, instantiating
// items, etc. which also need to happen in the context of a transaction
// but which the transaction class does not necessarily know about
// itself - or at least, not in any detail. Since the libcdl core is
// intended to be useful in various contexts, some sort of extensibility
// is essential.
//
// This is achieved by an auxiliary class, CdlTransactionCommitCancelOp.
// Clients of the transaction class can have their own utility class
// which derives from this, and create suitable objects. The transaction
// class maintains a vector of the pending commit/cancel operations.
//
// Each CdlTransactionCommitCancelOp object has two member functions,
// one for when the transaction gets committed and one for when it
// gets cancelled. If a sub-transaction gets committed then its
// pending ops are transferred across to the parent, allowing the
// parent to be cancelled sensibly: the commit ops only get run for
// the toplevel transaction. If a sub-transaction gets cancelled then
// the pending ops are invoked immediately.
//
// There is an assumption that commit/cancel ops get executed strictly
// in FIFO order. Specifically, commit ops get run from first one to
// the last one, allowing later operations in the transaction to
// overwrite earlier ones. Cancel ops get run in reverse order.
class CdlTransactionCommitCancelOp {
friend class CdlTest;
public:
CdlTransactionCommitCancelOp() { }
virtual ~CdlTransactionCommitCancelOp() { };
// The default implementations of both of these do nothing.
// Derived classes should override at least one of these
// functions.
virtual void commit(CdlTransaction transaction) {
CYG_UNUSED_PARAM(CdlTransaction, transaction);
}
virtual void cancel(CdlTransaction transaction) {
CYG_UNUSED_PARAM(CdlTransaction, transaction);
}
protected:
private:
};
//}}}
//{{{ CdlTransaction class
class CdlTransactionBody {
friend class CdlTest;
friend class CdlConflictBody;
friend class CdlValuableBody;
public:
// Create a toplevel transaction
static CdlTransaction make(CdlToplevel);
virtual ~CdlTransactionBody();
CdlToplevel get_toplevel() const;
// Or a sub-transaction. Usually these are created in the context of
// a conflict that is being resolved.
CdlTransaction make(CdlConflict = 0);
CdlTransaction get_parent() const;
CdlConflict get_conflict() const;
// Commit all the changes. Essentially this means transferring
// all of the per-transaction data to the toplevel, and then
// invoking the transaction callback. All propagation, inference,
// etc. should happen before the commit()
// This routine can also be used to transfer changes from a
// sub-transaction to the parent.
void commit();
// A variant of the commit() operation can be used to
// store a sub-transaction in a conflict's solution vector,
// rather than updating the parent transaction. This is useful
// for inferred solutions which cannot be applied without
// user confirmation
void save_solution();
// Can a solution held in a sub-transaction be applied without
// e.g. overwriting a user value with an inferred value?
bool user_confirmation_required() const;
// If the user has explicitly changed a value in the current transaction
// then the inference engine should not undo this or suggest a solution
// that will undo the change.
bool changed_by_user(CdlValuable) const;
// A variant which is used for checking the hierarchy when disabling
// a container
bool subnode_changed_by_user(CdlContainer) const;
// Is one transaction preferable to another?
bool is_preferable_to(CdlTransaction) const;
// Find out about per-transaction conflicts. This is particularly
// useful for the inference callback. The other containers can
// be accessed as well, for completeness.
const std::list<CdlConflict>& get_new_conflicts() const;
const std::list<CdlConflict>& get_new_structural_conflicts() const;
const std::vector<CdlConflict>& get_deleted_conflicts() const;
const std::vector<CdlConflict>& get_deleted_structural_conflicts() const;
const std::vector<CdlConflict>& get_resolved_conflicts() const ;
const std::list<CdlConflict>& get_global_conflicts_with_solutions() const;
const std::map<CdlValuable, CdlValue>& get_changes() const;
const std::set<CdlNode>& get_activated() const;
const std::set<CdlNode>& get_deactivated() const;
const std::set<CdlValuable>& get_legal_values_changes() const;
// Manipulate the current set of conflicts, allowing for nested
// transactions and toplevel conflicts as well.
void clear_conflict(CdlConflict);
bool has_conflict_been_cleared(CdlConflict);
bool has_conflict(CdlNode, bool (*)(CdlConflict));
CdlConflict get_conflict(CdlNode, bool (*)(CdlConflict));
void get_conflicts(CdlNode, bool (*)(CdlConflict), std::vector<CdlConflict>&);
void clear_conflicts(CdlNode, bool (*)(CdlConflict));
bool has_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
CdlConflict get_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
void get_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector<CdlConflict>&);
void clear_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
bool has_structural_conflict(CdlNode, bool (*)(CdlConflict));
CdlConflict get_structural_conflict(CdlNode, bool (*)(CdlConflict));
void get_structural_conflicts(CdlNode, bool (*)(CdlConflict), std::vector<CdlConflict>&);
void clear_structural_conflicts(CdlNode, bool (*)(CdlConflict));
bool has_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
CdlConflict get_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
void get_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector<CdlConflict>&);
void clear_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
// During the inference callback the user may decide to
// apply one or more of the solutions.
void apply_solution(CdlConflict);
void apply_solutions(const std::vector<CdlConflict>&);
void apply_all_solutions();
// Cancel all the changes done in this transaction. Essentially
// this just involves clearing out all the STL containers.
void cancel();
// Support for commit/cancel ops. These are used for
// e.g. load and unload operations.
void add_commit_cancel_op(CdlTransactionCommitCancelOp *);
void cancel_last_commit_cancel_op();
CdlTransactionCommitCancelOp* get_last_commit_cancel_op() const;
const std::vector<CdlTransactionCommitCancelOp*>& get_commit_cancel_ops() const;
// Propagation support
void add_active_change(CdlNode);
void add_legal_values_change(CdlValuable);
void propagate();
bool is_propagation_required() const;
// Inference engine support.
void resolve(int = 0); // Process the new conflicts raised by this transaction
void resolve(CdlConflict, int = 0);
void resolve(const std::vector<CdlConflict>&, int = 0);
// An auxiliary function called by the inference engine to perform recursion
bool resolve_recursion(int);
// This function combines propagation, inference, and commit
// in one easy-to-use package
void body();
// Changes.
// There is a call to get hold of a CdlValue reference. Modifications
// should happen via a sequence of the form:
//
// valuable->set_value(transact, ...)
// const CdlValue& old_value = transact->get_whole_value(CdlValuable);
// CdlValue new_value = old_value;
// <modify new_value>
// transact->set_whole_value(CdlValuable, old_value, new_value);
//
// When appropriate the get_whole_value() call takes care of
// updating the current conflict's solution_references vector. The
// set_whole_value() call updated the per-transaction changes map,
// and also stores sufficient information to support propagation.
// set_whole_value() requires both the old and new values, so
// that propagation can be optimized.
const CdlValue& get_whole_value(CdlConstValuable) const;
void set_whole_value(CdlValuable, const CdlValue&, const CdlValue&);
// Control over active vs. inactive also needs to happen inside
// transactions
bool is_active(CdlNode) const;
void set_active(CdlNode, bool);
// Callback and parameter settings
static void (*get_callback_fn())(const CdlTransactionCallback&);
static void set_callback_fn(void (*)(const CdlTransactionCallback&));
static void set_inference_callback_fn(CdlInferenceCallback);
static CdlInferenceCallback get_inference_callback_fn();
static void enable_automatic_inference();
static void disable_automatic_inference();
static bool is_automatic_inference_enabled();
static void set_inference_recursion_limit(int);
static int get_inference_recursion_limit();
// The override indicates the highest level of value source that the
// library can overwrite without needing user confirmation. The
// default value is CdlValueSource_Inferred, indicating that the
// library can overwrite default and inferred values but not
// wizard or user values.
static void set_inference_override(CdlValueSource);
static CdlValueSource get_inference_override();
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
private:
CdlTransactionBody(CdlToplevel, CdlTransaction, CdlConflict);
// The associated toplevel and optionally the parent transaction
// and the conflict being worked on
CdlToplevel toplevel;
CdlTransaction parent;
CdlConflict conflict;
// Per-transaction information. All value changes, new conflicts
// etc. first live in the context of a transaction. The global
// configuration only gets updated if the transaction is commited.
// There is also a vector of the pending commit/cancel ops.
std::vector<CdlTransactionCommitCancelOp*> commit_cancel_ops;
std::map<CdlValuable, CdlValue> changes;
std::list<CdlConflict> new_conflicts;
std::list<CdlConflict> new_structural_conflicts;
std::vector<CdlConflict> deleted_conflicts; // Existing global ones
std::vector<CdlConflict> deleted_structural_conflicts;
std::vector<CdlConflict> resolved_conflicts; // New ones already fixed by the inference engine
std::list<CdlConflict> global_conflicts_with_solutions;
std::set<CdlNode> activated;
std::set<CdlNode> deactivated;
std::set<CdlValuable> legal_values_changes;
bool dirty;
// Change propagation. It is necessary to keep track of all
// pending value changes, active changes, and of things being
// loaded or unloaded. The set_value() call is used to update the
// value_changes container.
std::deque<CdlValuable> value_changes;
std::deque<CdlNode> active_changes;
// Control over the inference engine etc.
static CdlInferenceCallback inference_callback;
static bool inference_enabled;
static int inference_recursion_limit;
static CdlValueSource inference_override;
static void (*callback_fn)(const CdlTransactionCallback&);
enum {
CdlTransactionBody_Invalid = 0,
CdlTransactionBody_Magic = 0x3f91e4df
} cdltransactionbody_cookie;
// Illegal operations
CdlTransactionBody();
CdlTransactionBody(const CdlTransactionBody &);
CdlTransactionBody& operator=(const CdlTransactionBody&);
};
//}}}
//{{{ CdlTransactionCallback
// ----------------------------------------------------------------------------
// The callback class is used to inform applications about all the
// changes that are happening, including side effects. Application
// code can install a callback function which gets invoked at the
// end of every transaction.
//
// NOTE: this implementation is preliminary. In particular it is
// not extensible, it only deals with changes relevant to software
// configurations.
class CdlTransactionCallback {
friend class CdlTest;
friend class CdlTransactionBody;
public:
~CdlTransactionCallback();
static void (*get_callback_fn())(const CdlTransactionCallback&);
static void set_callback_fn(void (*)(const CdlTransactionCallback&));
// Callback functions should be able to retrieve information
// about the current transaction and toplevel, to avoid the use
// of statics.
CdlTransaction get_transaction() const;
CdlToplevel get_toplevel() const;
// active_changes and legal_values_changes get updated as the
// transaction proceeds, so a set implementation is more
// efficient. The others get filled in during a commit operation.
// A transaction may result in multiple conflicts for a given node
// being eliminated, so again a set is appropriate. For the others
// there is no possibility of duplicates so a vector is better.
std::vector<CdlValuable> value_changes;
std::vector<CdlNode> active_changes;
std::vector<CdlValuable> legal_values_changes;
std::vector<CdlValuable> value_source_changes;
std::vector<CdlConflict> new_conflicts;
std::vector<CdlConflict> new_structural_conflicts;
std::vector<CdlNode> nodes_with_resolved_conflicts;
std::vector<CdlNode> nodes_with_resolved_structural_conflicts;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
protected:
private:
CdlTransactionCallback(CdlTransaction);
CdlTransaction transact;
// Illegal operation.
CdlTransactionCallback();
enum {
CdlTransactionCallback_Invalid = 0,
CdlTransactionCallback_Magic = 0x0cec3a95
} cdltransactioncallback_cookie;
};
//}}}
//{{{ CdlLocalTransaction
// ----------------------------------------------------------------------------
// A utility class to create a per-function transaction object which gets
// cleaned up automatically should an exception happen.
class CdlLocalTransaction {
friend class CdlTrest;
public:
CdlLocalTransaction(CdlToplevel toplevel) {
transaction = CdlTransactionBody::make(toplevel);
}
~CdlLocalTransaction() {
// The destructor may get invoked during exception handling.
// It is assumed that cancelling the transaction would be a
// good thing when that happens. Normal operation should
// go through the body() or commit() members, which clear
// the transaction field.
// There is a slight consistency here. Normally after a
// transaction commit the transaction object is still
// around. Here the transaction object get deleted. This
// is unlikely to matter in practice.
if (0 != transaction) {
transaction->cancel();
delete transaction;
}
}
CdlTransaction get() {
return transaction;
}
void body() {
transaction->body();
delete transaction;
transaction = 0;
}
void commit() {
transaction->commit();
delete transaction;
transaction = 0;
}
void propagate() {
transaction->propagate();
}
void destroy() {
if (0 != transaction) {
transaction->cancel();
delete transaction;
transaction = 0;
}
}
private:
CdlTransaction transaction;
CdlLocalTransaction();
};
//}}}
//}}}
//{{{ Build and define information
//{{{ Description
// ----------------------------------------------------------------------------
// There are two related concepts: buildable components, and
// definable components. The former typically refers to compiling
// sources files to produce libraries, although other types of build
// are possible. The latter refers to generating header files
// containing the current configuration data. Typically any loadable
// that is buildable is also definable, so that the source files can
// #include the appropriate generated headers and adapt to the
// configuration data that way. The inverse is not true: for example
// in HCDL it may be appropriate to generate a header file but there
// is nothing to be compiled, device drivers are software packages.
//
// The relevant base classes are as follows:
//
// 1) CdlBuildable - this object can have build-related properties.
// All buildables are also valuables.
// 2) CdlBuildLoadable - this is a base class for loadables, providing
// some extra properties that are relevant for
// loadables that can involve builds.
// 3) CdlDefinable - this object can result in #define's in a
// header file. All exportables are also
// valuables.
// 4) CdlDefineLoadable - this is a base class for any loadables that
// can contain buildables.
//
// Support for both buildable and exportable components is part of the
// core library for now. This may change in future, depending on how
// many CDL variants get implemented.
//
// There are various properties related to building. First, the
// ones applicable to the CdlBuildLoadable class.
//
// 1) library xyz.
// This specifies the default library for anything built in this
// loadable. If there is no library property then it defaults to
// libtarget.a (or rather to a class static that happens to be
// initialized to libtarget.a)
//
// 2) include_dir <dir>.
// This specifies where the loadable's exported header files should
// end up. The default value is the toplevel, but e.g. the eCos
// kernel specifies an include_dir of cyg/kernel. Note that fixed
// header files are associated with buildables, not definables,
// the latter deal with generated header files only.
//
// 3) include_files <hdr1 hdr2 ...>
// The recommended directory hierarchy for non-trivial packages
// involves separate subdirectories src, include, cdl, doc, and
// test. This is too heavyweight for very simple packages where it
// is better to keep everything in just one directory. However that
// introduces a potential conflict between public and private
// header files, which can be resolved by the include_files
// property. The actual rules are:
//
// a) if there an include_files property, that lists all the
// headers that should be exported.
//
// b) else if there is an include subdirectory, it is assumed that
// all files below that should be exported.
//
// c) otherwise all files matching a suitable glob pattern should
// be exported. The default pattern is *.h *.hxx *.inl, but can
// be overwritten.
//
// 4) makefile <file>
// This allows component developers to provide a GNU makefile to be
// used for building, rather than specify the relevant information
// via properties.
// NOTE: this property is ignored for now. It is roughly
// equivalent to a custom build step where the command is
// "make -C <dir> -f <file>", but in addition it is necessary to
// worry about phony targets for default, clean, etc.
//
// A DefineLoadable adds the following property:
//
// 1) define_header <file>
// This specifies the header file that will be generated. If this
// property is absent then the library will generate a default one
// based on the loadable's name, by discarding everything up to and
// including the first underscore, lowercasing the rest, and
// appending .h. For example, CYGPKG_KERNEL would result in a
// header file kernel.h.
//
// Hardware packages have an implicit "define_header hardware.h"
// property.
//
// A buildable has the following properties:
//
// 1) compile [-library xyz] <file1> <file2> ...
// This specifies one or more files that need to be compiled.
// By default the resulting object files will go into the
// current library (set via a higher-level library or
// defaulting to libtarget.a).
//
// Legitimate filename suffixes for compile statements are .c, .cxx
// and .S. Further suffixes may be supported in future. In the
// long term we will need some external data files defining how
// the various suffixes should be handled.
//
// Associated with every compilation are details of the compiler to
// be used and the compiler flags. For now no attempt is made
// to do anything interesting in this area, although there is
// sufficient information in the database for the needs of
// command line tools.
//
// Longer term there are complications. Packages may want some
// control over the compiler flags that should be used, e.g.
// "requires {!(flags ~= ".*-fno-rtti.*")}" to guarantee that the
// compiler flags do not include -fno-rtti, rather useful if the
// package's source code depends on that language feature. Mixed
// architecture systems (e.g. ARM/Thumb) will cause problems when
// it comes to selecting the compiler. The exact means by which
// all this will work is not yet clear.
//
// 2) object [-library xyz] <file1> <file2> ...
// This specifies one or more pre-built object files that should
// go into the appropriate library.
//
// The problem here is coping with different architectures, and for
// many architectures it will also be necessary to worry about
// multilibs. Third party component vendors are unlikely to supply
// separate object files for every supported architecture and every
// valid multilib within those architectures, so there are
// constraints on the multilib-related compiler flags used for
// building other packages and the application itself.
//
// NOTE: this property is ignored for now.
//
// 3) make_object [-library xyz] [-priority pri] <file> <makefile fragment>
//
// For example:
//
// make_object toyslock.o {
// toyslock.o : toyslock.y
// yacc toyslock.y
// $(CC) $(CFLAGS) -o toyslock.o y.tab.c
// }
//
// This defines a custom build step for an object file that
// should go into a particular directory. A makefile syntax
// is used to define the rule simply because it is likely
// to be familiar to package developers, and does not
// imply that the builds will happen via a makefile.
//
// The optional priority field indicates at which stage during
// the build the rule should trigger. The default value is
// 100, which is the same as for all files specified in
// "compile" properties. A lower value means that the object
// will be generated earlier. Libraries are generated at
// priority 200, and "make" properties normally execute at
// priority 300.
// NOTE: it is not clear yet whether supporting priorities
// in this way is a good idea, or whether the dependencies
// information could be used instead.
//
// Unresolved issues:
//
// a) what commands can be used in the build rules? There
// should be a core set of supported commands, as per
// an eCos toolchain build. It should also be possible
// for packages to provide their own host tools.
//
// For sourceware folks, moving away from a single toolchain
// tarball and expecting them to download and install
// egcs, binutils and gdb separately is actually a bad
// idea in this regard, it makes it much more likely that
// some users will have an incomplete tools installation and
// hence that builds will fail.
//
// b) there is an obvious need for variable substitution in the
// rules, e.g. $(CC). At what stage do these variables get
// expanded, and where does the required information live?
//
// c) who is responsible for header file dependency analysis?
// Should the rules be modified automatically to do this,
// or do we leave this to the package developer? It may be
// very hard to do the former, but the latter will cause
// problems for IDE integration.
//
// d) in which directory will the rules get run? What prevents
// filename conflicts between different packages?
//
// NOTE: make_object is not actually required just yet, but the
// issues are much the same as for the "make" property which is
// required.
//
// 4) make [-priority pri] <target> <makefile fragment>
//
// For example:
//
// make target.ld {
// target.ld : arm.ld
// $(CC) -E -P -xc $(CFLAGS) -o $@ $<
// }
//
// This defines a custom build step for a target that is not going
// to end up in a library. The main such targets at the moment are
// the linker script, vectors.o, and extras.o, but there may well
// be others in future.
//
// The default priority for "make" properties is 300, which means
// that the build rules trigger after all normal compilations and
// after the libraries are generated. It is possible to specify
// custom build steps that should run before any compilations
// using a priority < 100.
//
// Unresolved issues:
//
// a) what commands can be used?
//
// b) variable substitution?
//
// c) header file dependency analysis?
//
// d) directories and filenames?
//
// e) where should the resulting files end up? Currently they can
// all go into $(PREFIX)/lib, but in the long term we may
// need to be a bit more flexible.
//
// 5) build_proc <tcl code>
//
// This defines some Tcl code that should be run prior to any
// build, for example to generate a source file. It must run
// within the appropriate loadable's Tcl interpreter so that
// it can query the current configuration.
//
// NOTE: this property is not implemented yet.
//
//
// A definable has the following properties:
//
// 1) no_define
// Usually the library will generate either one or two #define's
// for every definable, inside the current header file. This can be
// suppressed by the no_define property, which is typically
// accompanied by some other #define-related property such as
// define_proc or define.
//
// 2) define [-file <filename>] [-format <format_string>] symbol
// This will result in an additional #define for the specified
// symbol in the specified file. The only filenames that are valid
// are the loadable's current filename (as per define_header), and
// the global header file system.h. Use of the latter should be
// avoided.
//
// The optional format string behaves as per the define_format
// property below.
//
// 3) define_format <format_string>
// This is only relevant for booldata or data flavors. By default
// two #define's will be generated (assuming the valuable is active
// and enabled):
//
// #define <symbol> value
// #define <symbol>_value
//
// The latter will only be generated if the resulting symbol is
// a valid C preprocessor symbol, and is intended to allow the
// use of #ifdef as well as #ifdef (useful if the value is
// non-numerical).
//
// The define_format property provides control over the first of
// these two #defines. The net result is that the #define will be
// generated by evaluating the following Tcl fragment:
//
// set result "#define <symbol> [<format> <value>]"
//
// Command and variable substitution are available if desired,
// but for anything that complicated the define_proc property
// is normally more useful.
//
// define_format is only applicable to the default definition,
// so it cannot be used in conjunction with no_define. The
// define property supports a -format option.
//
// 4) define_proc <tclcode>
// This specifies some Tcl code that should be run when header
// file generation takes place, in addition to any #define's
// generated by default or courtesy of define properties.
// The define_proc property is commonly used in conjunction with
// no_define, but this is not required.
//
// There will be two channels already set up: cdl_header
// for the current loadable, and cdl_system_header for system.h.
// Writing data to system.h should be avoided.
//
// 5) if_define <condition> <symbol>
// This property provides direct support for a common programming
// paradigm. It allows direct generation of code like the
// following:
//
// #ifdef CYGSRC_TOYS_BLOCKS
// # define CYGDBG_INFRA_USE_PRECONDITIONS 1
// #endif
//
// In this case CYGSRC_TOYS_BLOCKS is the condition and
// CYGDBG_INFRA_USE_PRECONDITIONS is the symbol. The
// #ifdef/#define sequence will be generated in addition to
// any other #define's resulting from the default behaviour,
// the define property, or the define_proc property. It is
// not affected by no_define.
//}}}
//{{{ The build process
// ----------------------------------------------------------------------------
// For command-line operation the steps involved in doing a build are:
//
// 1) work out what needs to be built.
//
// 2) generate a build and install tree. This involves making sure that
// the various directories exist and are accessible.
//
// 3) generate or update the toplevel makefile.
//
// 4) generate the configuration header files.
//
// For operation in an IDE steps (2) and (3) will be handled by
// different code.
//
// There is a library call to get hold of all the build information:
//
// config->get_build_info(CdlBuildInfo &info);
//
// This erases anything previously present in the build-info argument
// and fills in the information appropriate to the current
// configuration, essentially by walking down the list of loadables
// and each loadable's list of nodes, checking for BuildLoadables
// and Buildables along the way. The BuildInfo class is defined
// further down.
//
// An alternative library call can be used to find out about all
// possible files that need to be compiled etc., irrespective of the
// current configuration settings. This could be useful when it
// comes to letting the user control compiler flags etc.
//
// config->get_all_build_info(CdlBuildInfo& info);
//
// There is another library call for step (4):
//
// config->generate_config_headers(std::string directory)
//
// This will create or update the header files appropriate to
// the current configuration. Temporary files will be generated,
// diff'ed with the current version, and existing files will
// only be modified if necessary. The directory argument
// indicates where the header files should go, i.e. it should
// be the equivalent of $(PREFIX)/include/pkgconf
//
// This library call does not delete any files it does not
// recognize, that is the responsibility of higher-level code.
// It is possible to get or update a list of the files that
// will be generated:
//
// config->get_config_headers(std::vector<std::string>& headers)
//
// The argument will be cleared if necessary and then filled in with
// the current set of header files. Higher level code can compare the
// result with the current files in the directory and take or suggest
// remedial action.
//
// There is also a library call which combines all four stages:
//
// config->generate_build_tree(std::string build_tree, std::string prefix = $(BUILD)/install)
//
//
// The order in which the various build steps happen is important.
//
// 1) non-configuration headers must be copied from the component
// repository into $(PREFIX)/include. No compiles can happen
// before this.
//
// 2) all compile properties can happen in parallel. These have an
// effective priority of 100.
//
// 3) all make_object priorities can happen in parallel with
// compiles. These have a default priority of 100, but the
// priority can be modified.
//
// 4) the generated objects and any pre-built objects should be
// incorporated into the appropriate library. This happens
// at priority 200.
//
// 5) custom build steps associated with "make" properties should
// now run. These have a default priority of 300, but it is
// possible to override this.
//
// Usually all source files will come from the component repository,
// which means that they are read-only. Ideally it should also be
// possible for a source file to be copied into the build tree and
// edited there, and subsequent builds should pick up the copy rather
// than the original. The build data generated by libcdl will always
// be in the form of relative pathnames to facilitate this.
//}}}
//{{{ CdlBuildInfo class
// ----------------------------------------------------------------------------
// Extracting the build information.
//
// libcdl.a defines the following classes related to build information.
//
// CdlBuildInfo
// CdlBuildInfo_Loadable
// CdlBuildInfo_Header
// CdlBuildInfo_Compile
// CdlBuildInfo_Object
// CdlBuildInfo_MakeObject
// CdlBuildInfo_Make
//
// The build information is organized on a per-loadable basis.
// Higher-level code may choose to flatten this or to keep the
// distinction. A CdlBuildInfo object is primarily a vector of
// CdlBuildInfo_Loadable objects. CdlBuildInfo objects can be created
// statically.
//
// In turn, each CdlBuildInfo_Loadable object is primarily a
// collection of five vectors, one each for Header, Compile, Object,
// MakeObject and Make.
//
// All pathnames in these data structures will use forward slashes as
// the directory separator, irrespective of the host platform. All
// pathnames will be relative.
struct CdlBuildInfo_Header {
std::string source; /* include/cyg_ass.h */
std::string destination; /* cyg/infra/cyg_ass.h */
};
struct CdlBuildInfo_Compile {
std::string library; /* libtarget.a */
std::string source; /* src/fancy.cxx */
// Compiler and cflags data may be added in future.
};
struct CdlBuildInfo_Object {
std::string library; /* libtarget.a */
std::string object; /* obj/hello.o */
};
struct CdlBuildInfo_MakeObject {
cdl_int priority; /* 100 */
std::string library; /* libtarget.a */
std::string object; /* toyslock.o */
std::string deps; /* toyslock.y */
/*
It is not clear whether the deps field is actually useful in the
context of IDE integration, but see the note about arm.inc
above.
*/
std::string rules;
/*
A typical value for "rules" might be:
yacc toyslock.y
$(CC) $(CFLAGS) -o toyslock.o y.tab.c
Leading white space is not significant. Newlines are significant.
Backslash escapes in the text will not have been processed yet.
*/
};
struct CdlBuildInfo_Make {
cdl_int priority; /* 300 */
std::string target; /* extras.o */
std::string deps; /* libextras.a */
std::string rules;
/*
Something like:
$(CC) $(ARCHFLAGS) $(LDARCHFLAGS) -nostdlib -Wl,-r -Wl,--whole-archive $(PREFIX)/lib/libextras.a -o $(PREFIX)/lib/extras.o
*/
};
class CdlBuildInfo_Loadable {
friend class CdlTest;
public:
std::string name; /* CYGPKG_INFRA */
std::string directory; /* infra/current */
std::vector<CdlBuildInfo_Header> headers;
std::vector<CdlBuildInfo_Compile> compiles;
std::vector<CdlBuildInfo_Object> objects;
std::vector<CdlBuildInfo_MakeObject> make_objects;
std::vector<CdlBuildInfo_Make> makes;
protected:
private:
};
class CdlBuildInfo {
friend class CdlTest;
public:
std::vector<CdlBuildInfo_Loadable> entries;
protected:
private:
};
//}}}
//{{{ CdlBuildLoadable
// ----------------------------------------------------------------------------
// BuildLoadables are derived from Loadables and are appropriate for
// any loadables that can contain build information. There are a
// number of properties applicable at this level: makefile,
// include_dir, include_files and library. The main interface of
// interest is update_build_info().
//
// It is likely that all BuildLoadables are also Buildables, but this
// is not required.
class CdlBuildLoadableBody : virtual public CdlLoadableBody
{
friend class CdlTest;
public:
virtual ~CdlBuildLoadableBody();
// This is the main way to extract information about what should
// get built. It takes into account the active and enabled states,
// as appropriate.
void update_build_info(CdlBuildInfo&) const;
// An alternative which ignores the active and enabled states.
void update_all_build_info(CdlBuildInfo&) const;
// Property parsers and validation code appropriate for a
// build-loadable object such as makefile
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_library(CdlInterpreter, int, const char*[]);
static int parse_makefile(CdlInterpreter, int, const char*[]);
static int parse_include_dir(CdlInterpreter, int, const char*[]);
static int parse_include_files(CdlInterpreter, int, const char*[]);
// By default any compiled files will go into libtarget.a, which
// is the default value for this variable. Individual applications may
// specify an alternative default library.
static char* default_library_name;
// When filling in a build_info structure the library needs to know
// what constitutes a header file. A glob pattern can be used for this.
// NOTE: in the long term this should come out of a data file.
static char* default_headers_glob_pattern;
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlBuildLoadableBody();
private:
enum {
CdlBuildLoadableBody_Invalid = 0,
CdlBuildLoadableBody_Magic = 0x55776643
} cdlbuildloadablebody_cookie;
// Illegal operations
CdlBuildLoadableBody(const CdlBuildLoadableBody&);
CdlBuildLoadableBody& operator=(const CdlBuildLoadableBody&);
};
//}}}
//{{{ CdlBuildable
// ----------------------------------------------------------------------------
// Buildable objects can have properties such as compile and
// make_object. These properties are not normally accessed
// directly. Instead there is a member function to update a
// CdlBuildInfo_Loadable object.
//
// The build properties for a given buildable have an effect iff
// that buildable is active, and in addition if the buildable is also
// a valuable then it must be enabled.
class CdlBuildableBody : virtual public CdlNodeBody
{
friend class CdlTest;
public:
virtual ~CdlBuildableBody();
// This is the main way to extract information about what should
// get built. It takes into account the active and enabled states,
// as appropriate. The second argument indicates the default
// library for the current loadable.
void update_build_info(CdlBuildInfo_Loadable&, std::string) const;
// An alternative which ignores the active and enabled states.
void update_all_build_info(CdlBuildInfo_Loadable&, std::string) const;
// Add property parsers and validation code appropriate for a
// buildable object such as compile and make_object
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_build_proc(CdlInterpreter, int, const char*[]);
static int parse_compile(CdlInterpreter, int, const char*[]);
static int parse_make(CdlInterpreter, int, const char*[]);
static int parse_make_object(CdlInterpreter, int, const char*[]);
static int parse_object(CdlInterpreter, int, const char*[]);
static bool split_custom_build_step(std::string /* data */, std::string& /* target */, std::string& /* deps */,
std::string& /* rules*/, std::string& /* error_msg */);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlBuildableBody();
private:
enum {
CdlBuildableBody_Invalid = 0,
CdlBuildableBody_Magic = 0x16eb1c04
} cdlbuildablebody_cookie;
// Illegal operations
CdlBuildableBody(const CdlBuildableBody&);
CdlBuildableBody& operator=(const CdlBuildableBody&);
};
//}}}
//{{{ CdlDefineLoadable
// ----------------------------------------------------------------------------
// DefineLoadables are derived from Loadables and are appropriate for
// any loadables that can result in generated header files containing
// configuration data. There is one applicable property,
// define_header. The main interface of interest is
// generate_config_headers().
class CdlDefineLoadableBody : virtual public CdlLoadableBody
{
friend class CdlTest;
public:
virtual ~CdlDefineLoadableBody();
// Update the header file for this loadable. The first argument
// is a channel to the loadable-specific header file. The second
// argument is a channel to the global header file.
void generate_config_header(Tcl_Channel, Tcl_Channel) const;
// What header file should be generated for this loadable?
virtual std::string get_config_header() const;
// Add property parsers and validation code.
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_define_header(CdlInterpreter, int, const char*[]);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlDefineLoadableBody();
private:
enum {
CdlDefineLoadableBody_Invalid = 0,
CdlDefineLoadableBody_Magic = 0x7e211709
} cdldefineloadablebody_cookie;
// Illegal operations
CdlDefineLoadableBody(const CdlDefineLoadableBody&);
CdlDefineLoadableBody& operator=(const CdlDefineLoadableBody&);
};
//}}}
//{{{ CdlDefinable
// ----------------------------------------------------------------------------
// Definables are derived from Valuables and provide support for
// outputting a configuration header file.
class CdlDefinableBody : virtual public CdlValuableBody
{
friend class CdlTest;
public:
virtual ~CdlDefinableBody();
// Update the header file for this definable. The loadable's Tcl
// interpreter will already have channels cdl_header and
// cdl_system_header set up appropriately.
void generate_config_header( Tcl_Channel, Tcl_Channel) const;
// Add property parsers and validation code.
static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
void check_properties(CdlInterpreter);
static int parse_define(CdlInterpreter, int, const char*[]);
static int parse_define_format(CdlInterpreter, int, const char*[]);
static int parse_define_proc(CdlInterpreter, int, const char*[]);
static int parse_if_define(CdlInterpreter, int, const char*[]);
static int parse_no_define(CdlInterpreter, int, const char*[]);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
protected:
CdlDefinableBody();
private:
enum {
CdlDefinableBody_Invalid = 0,
CdlDefinableBody_Magic = 0x65a2c95a
} cdldefinablebody_cookie;
// Illegal operations
CdlDefinableBody(const CdlDefinableBody&);
CdlDefinableBody& operator=(const CdlDefinableBody&);
};
//}}}
//}}}
//{{{ CdlDialog
// ----------------------------------------------------------------------------
// A dialog simply inherits from CdlUserVisible and provides convenient
// access to several dialog-specific properties.
class CdlDialogBody :
public virtual CdlUserVisibleBody,
public virtual CdlParentableBody
{
friend class CdlTest;
public:
virtual ~CdlDialogBody();
// Dialogs may be enabled or disabled globally. This affects
// CdlValuable::get_widget_hint() if the valuable has an associated
// custom dialog.
static void disable_dialogs();
static void enable_dialogs();
static bool dialogs_are_enabled();
bool has_init_proc() const;
bool has_update_proc() const;
const cdl_tcl_code& get_init_proc() const;
const cdl_tcl_code& get_update_proc() const;
const cdl_tcl_code& get_display_proc() const;
const cdl_tcl_code& get_confirm_proc() const;
const cdl_tcl_code& get_cancel_proc() const;
static int parse_dialog(CdlInterpreter, int, const char*[]);
static int parse_display_proc(CdlInterpreter, int, const char*[]);
static int parse_update_proc(CdlInterpreter, int, const char*[]);
// Persistence support. Dialogs should just be ignored when it
// comes to saving and restoring files.
virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
// The constructor only gets invoked from inside parse_dialog()
CdlDialogBody(std::string);
static bool dialogs_enabled;
enum {
CdlDialogBody_Invalid = 0,
CdlDialogBody_Magic = 0x3f4df391
} cdldialogbody_cookie;
// Illegal operations. The dialog name must be known at the time
// that the object is constructed.
CdlDialogBody();
CdlDialogBody(const CdlDialogBody&);
CdlDialogBody& operator=(const CdlDialogBody&);
};
//}}}
//{{{ CdlWizard
// ----------------------------------------------------------------------------
// A wizard is very much like a dialog, just a different set of properties.
class CdlWizardBody :
public virtual CdlUserVisibleBody,
public virtual CdlParentableBody
{
friend class CdlTest;
public:
virtual ~CdlWizardBody();
bool has_init_proc() const;
bool has_decoration_proc() const;
const cdl_tcl_code& get_init_proc() const;
const cdl_tcl_code& get_decoration_proc() const;
const cdl_tcl_code& get_confirm_proc() const;
const cdl_tcl_code& get_cancel_proc() const;
bool has_screen(cdl_int) const;
cdl_int get_first_screen_number() const;
const cdl_tcl_code& get_first_screen() const;
const cdl_tcl_code& get_screen(cdl_int) const;
static int parse_wizard(CdlInterpreter, int, const char*[]);
static int parse_cancel_proc(CdlInterpreter, int, const char*[]);
static int parse_confirm_proc(CdlInterpreter, int, const char*[]);
static int parse_decoration_proc(CdlInterpreter, int, const char*[]);
static int parse_init_proc(CdlInterpreter, int, const char*[]);
static int parse_screen(CdlInterpreter, int, const char*[]);
// Persistence support. Wizards should just be ignored when it
// comes to saving and restoring files.
virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
// The constructor only gets invoked from inside parse_wizard().
CdlWizardBody(std::string);
// Illegal operations.
CdlWizardBody();
CdlWizardBody(const CdlWizardBody&);
CdlWizardBody& operator=(const CdlWizardBody&);
enum {
CdlWizardBody_Invalid = 0,
CdlWizardBody_Magic = 0x4ec1c39a
} cdlwizardbody_cookie;
};
//}}}
//{{{ CdlInterface class
// ----------------------------------------------------------------------------
// Similarly for interfaces.
class CdlInterfaceBody : public virtual CdlNodeBody,
public virtual CdlUserVisibleBody,
public virtual CdlValuableBody,
public virtual CdlParentableBody,
public virtual CdlBuildableBody,
public virtual CdlDefinableBody
{
friend class CdlTest;
public:
~CdlInterfaceBody();
void get_implementers(std::vector<CdlValuable>&) const;
void recalculate(CdlTransaction);
static int parse_interface(CdlInterpreter, int, const char*[]);
// Persistence support. The interface data cannot sensibly be modified
// by users, it is all calculated. However it is useful to have the
// interface data present in the saved file so that users can examine
// dependencies etc.
virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
static void initialize_savefile_support(CdlToplevel);
static int savefile_interface_command(CdlInterpreter, int, const char*[]);
bool was_generated() const;
virtual bool is_modifiable() const;
virtual std::string get_class_name() const;
bool check_this(cyg_assert_class_zeal = cyg_quick) const;
CYGDBG_DECLARE_MEMLEAK_COUNTER();
private:
CdlInterfaceBody(std::string, bool /* generated */);
bool generated;
enum {
CdlInterfaceBody_Invalid = 0,
CdlInterfaceBody_Magic = 0x67f7fbe5
} cdlinterfacebody_cookie;
CdlInterfaceBody();
CdlInterfaceBody(const CdlInterfaceBody&);
CdlInterfaceBody& operator=(const CdlInterfaceBody&);
};
//}}}
#endif /* !__CDLCORE_HXX */
// EOF cdlcore.hxx
|