[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413] [0414] [0415] [0416] [0417] [0418] [0419] [0420] [0421] [0422] [0423] [0424] [0425] [0426] [0427] [0428] [0429] [0430] [0431] [0432] [0433] [0434] [0435] [0436] [0437] [0438] [0439] [0440] [0441] [0442] [0443] [0444] [0445] [0446] [0447] [0448] [0449] [0450] [0451] [0452] [0453] [0454] [0455] [0456] [0457] [0458] [0459] [0460] [0461] [0462] [0463] [0464] [0465] [0466] [0467] [0468] [0469] [0470] [0471] [0472] [0473] [0474] [0475] [0476] [0477] [0478] [0479] [0480] [0481] [0482] [0483] [0484] [0485] [0486] [0487] [0488] [0489] [0490] [0491] [0492] [0493] [0494] [0495] [0496] [0497] [0498] [0499] [0500] [0501] [0502] [0503] [0504] [0505] [0506] [0507] [0508] [0509] [0510] [0511] [0512] [0513] [0514] [0515] [0516] [0517] [0518] [0519] [0520] [0521] [0522] [0523] [0524] [0525] [0526] [0527] [0528] [0529] [0530] [0531] [0532] [0533] [0534] [0535] [0536] [0537] [0538] [0539] [0540] [0541] [0542] [0543] [0544] [0545] [0546] [0547] [0548] [0549] [0550] [0551] [0552] [0553] [0554] [0555] [0556] [0557] [0558] [0559] [0560] [0561] [0562] [0563] [0564] [0565] [0566] [0567] [0568] [0569] [0570] [0571] [0572] [0573] [0574] [0575] [0576] [0577] [0578] [0579] [0580] [0581] [0582] [0583] [0584] [0585] [0586] [0587] [0588] [0589] [0590] [0591] [0592] [0593] [0594] [0595] [0596] [0597] [0598] [0599] [0600] [0601] [0602] [0603] [0604] [0605] [0606] [0607] [0608] [0609] [0610] [0611] [0612] [0613] [0614] [0615] [0616] [0617] [0618] [0619] [0620] [0621] [0622] [0623] [0624] [0625] [0626] [0627] [0628] [0629] [0630] [0631] [0632] [0633] [0634] [0635] [0636] [0637] [0638] [0639] [0640] [0641] [0642] [0643] [0644] [0645] [0646] [0647] [0648] [0649] [0650] [0651] [0652] [0653] [0654] [0655] [0656] [0657] [0658] [0659] [0660] [0661] [0662] [0663] [0664] [0665] [0666] [0667] [0668] [0669] [0670] [0671] [0672] [0673] [0674] [0675] [0676] [0677] [0678] [0679] [0680] [0681] [0682] [0683] [0684] [0685] [0686] [0687] [0688] [0689] [0690] [0691] [0692] [0693] [0694] [0695] [0696] [0697] [0698] [0699] [0700] [0701] [0702] [0703] [0704] [0705] [0706] [0707] [0708] [0709] [0710] [0711] [0712] [0713] [0714] [0715] [0716] [0717] [0718] [0719] [0720] [0721] [0722] [0723] [0724] [0725] [0726] [0727] [0728] [0729] [0730] [0731] [0732] [0733] [0734] [0735] [0736] [0737] [0738] [0739] [0740] [0741] [0742] [0743] [0744] [0745] [0746] [0747] [0748] [0749] [0750] [0751] [0752] [0753] [0754] [0755] [0756] [0757] [0758] [0759] [0760] [0761] [0762] [0763] [0764] [0765] [0766] [0767] [0768] [0769] [0770] [0771] [0772] [0773] [0774] [0775] [0776] [0777] [0778] [0779] [0780] [0781] [0782] [0783] [0784] [0785] [0786] [0787] [0788] [0789] [0790] [0791] [0792] [0793] [0794] [0795] [0796] [0797] [0798] [0799] [0800] [0801] [0802] [0803] [0804] [0805] [0806] [0807] [0808] [0809] [0810] [0811] [0812] [0813] [0814] [0815] [0816] [0817] [0818] [0819] [0820] [0821] [0822] [0823] [0824] [0825] [0826] [0827] [0828] [0829] [0830] [0831] [0832] [0833] [0834] [0835] [0836] [0837] [0838] [0839] [0840] [0841] [0842] [0843] [0844] [0845] [0846] [0847] [0848] [0849] [0850] [0851] [0852] [0853] [0854] [0855] [0856] [0857] [0858] [0859] [0860] [0861] [0862] [0863] [0864] [0865] [0866] [0867] [0868] [0869] [0870] [0871] [0872] [0873] [0874] [0875] [0876] [0877] [0878] [0879] [0880] [0881] [0882] [0883] [0884] [0885] [0886] [0887] [0888] [0889] [0890] [0891] [0892] [0893] [0894] [0895] [0896] [0897] [0898] [0899] [0900] [0901] [0902] [0903] [0904] [0905] [0906] [0907] [0908] [0909] [0910] [0911] [0912] [0913] [0914] [0915] [0916] [0917] [0918] [0919] [0920] [0921] [0922] [0923] [0924] [0925] [0926] [0927] [0928] [0929] [0930] [0931] [0932] [0933] [0934] [0935] [0936] [0937] [0938] [0939] [0940] [0941] [0942] [0943] [0944] [0945] [0946] [0947] [0948] [0949] [0950] [0951] [0952] [0953] [0954] [0955] [0956] [0957] [0958] [0959] [0960] [0961] [0962] [0963] [0964] [0965] [0966] [0967] [0968] [0969] [0970] [0971] [0972] [0973] [0974] [0975] [0976] [0977] [0978] [0979] [0980] [0981] [0982] [0983] [0984] [0985] [0986] [0987] [0988] [0989] [0990] [0991] [0992] [0993] [0994] [0995] [0996] [0997] [0998] [0999] [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]
/*****************************************************************************/ /* render.c This renders HTML5 syntax. https://www.w3.org/TR/html50/ https://www.w3.org/TR/html52/ https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5 Some HTML tags designated self-closing https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags (<li>, <tr>, <th>, <td>) are left explicitly unclosed by this render engine. wasDOC TAGS ----------- There are basically two types of tag. First; those that have punctuation immediately following the introducing vbar. These are text highlight flags and generally continue up to the first alphabetic or period, escape or vbar character. They are intended as terse and syntactically efficient mechanisms to highlight narrative text. Second; an alphabetic keyword follows the introducing vbar. The keyword optionally can have trailing highlight and formatting punctuation and allied characters. For this purpose the heading tags (|0..|4 and |9) are considered keyword tags. A keyword tag commonly (but by no means exclusively) operates on an immediately following, vbar terminated parameter. Sometimes more than one. No white-space is permitted between the keyword tag and any parameter. Source documents may be made more readable by judicious use of the line-escape (\<LF>). The markup syntax has a lot of commonality but ultimately is pragmatic and some inconsistency is sprinkled throughout the application. Highlight and formatting characters similarly have much in common but ultimately prostrate themselves before what was necessary and worked. And, of course, the absence of a detailed design at the outset tends to manifest itself. Brief mnemonic for tags: |*bolded text| |/italicised text| |-strikethrough text| |_underscored text| |=monospace text| |><centered text| |>>no wrap| |<<pre-wrap| |"text not HTML escaped|| |'class.some text| |&style.some text| |0Heading without TOC entry| |1Major Heading (toc 1)| |2Sub Heading (toc 1.2)| |3Further Sub Heading (toc 1.2.3)| |4LowestSub Heading (toc 1.2.3.4)| |5 n/a |6 n/a |7 n/a |8 n/a |9Cross-reference heading| |asis| completely unescaped text terminated by \n||||\n |block| block of content |code| function times2 (int num) { return num * 2; } | |draw| box drawing for simple diagrams |example| dashed line to delineate |inline| in-line block |prop| pre-formatted (proportional) text | |mono| monospace pre-formatted text | |note| note text | |^ paragraph break (must be followed by white space) |^+ paragraph indented |^- line break |ppage| page break when printed |toc| table of content inserted here |index| document index inserted here |insert|param| insert a file content, spawned command, or other data NOTE: alternates are personal preference |simple| begin simple list |sl| ditto |bullet| begin unordered list |ul| ditto |number| begin unordered list |ol| ditto |item| list item |li| ditto |& ditto ("shorthand" form) || end list NOTE: no explicit closure for table elements |table| table |tablular| table |row| row of cells |tr| ditto |~ ditto |head| header cell |tr| ditto |: ditto |data| data cell |td| ditto |. ditto || end of table |image|image-name.jpg|| |image|//host/image-name.png|This is the caption| |image|https://host/image-name.png|This is the caption| |link|The Heading Name|| |link|link-URL|caption|| |link|https://an.example/|This is an Example|| |link+|https://an.example/|=In a New Tab/Page|| |if| false |if|0| false |if|1| true |if|dynamic| a CGI script |if|static| not a CGI script |if|multi| multiple parts (chunked) |if|single| single part (not chunked) |if|hide| not visible unless ?nohide=1 |if|apache| apache server |if|wasd| WASD server |if|osu| osu server |elif|...| |else| |endif| |if|+| show conditional stack |if|-| disable show conditional stack |break| break as if the source was exhausted |exit| exit the document processor |hide| hide the HTML until a |resume| |insight!| a snapshot of the stack content |insight@| buttons to access the text and HTML and some stats |print| document section only in a printed version | |noprint| document section not in printed version | |style| set document style element |set|chunked=..| 1 enables, 0 let the client decide, -1 disables |set|idx=cols=..| 1, 2, 3, 4 columns in the index |set|idx=sort=..| index sorted 1, unsorted 0 |set|idx=collate=..| collation characters for index (26 alphabetics default) |set|insight=..| 1, 2, 3, 4 levels of informational |set|locale=..| set an aspect of C-locale (CTYPE) |set|navigate=..| 1 enables navigation arrows |set|note=..| set default (e.g. non-English) note heading |set|paginate=..| enable automatic pagination (horizontal rules) |set|table=margin=..| default table margin indicator |set|title=..| explicitly set the title of the document |set|toc=cols=..| 1, 2, 3, 4 columns in the main Table Of Content |set|toc2=..| secondry TOC is generated |set|toc2=cols=..| 1, 2, 3, 4 columns in the secondary Table Of Content |set|FLAG=..| set a flag value // comment to end-of-line (except inside text as-is) VERSION HISTORY --------------- 28-APR-2020 MGD rework memory management 25-JAN-2020 MGD add |draw| via drawThis() 07-JUL-2019 MGD bugfix; broken nested conditionals 21-FEB-2019 MGD initial */ /*****************************************************************************/ #include "wasdoc.h" #include "css.h" #include <locale.h> #include <descrip.h> #include <lnmdef.h> #include <starlet.h> #include <syidef.h> #include <cgilib.h> #ifndef STYLE_DEFAULT #define STYLE_DEFAULT "<style type=\"text/css\">\n</style>\n" #endif char styleDefault [] = STYLE_DEFAULT; extern int bvbar, dbug, CgiPlusCount, isCgi, isCgiPlus; extern char CopyrightDate [], SoftwareID [], SoftwareVersion []; /*****************************************************************************/ /* Parse the source text markup rendering the HTML document. */ int renderParse (struct wasdoc_st *docptr) { static char vtime [18]; static $DESCRIPTOR (vtimeDsc, vtime); static $DESCRIPTOR (faoDsc, "!17%D\0"); int ch, error, idx, length; char *aptr, *cptr, *sptr, *rowptr = NULL, *tagptr, *tptr, *zptr; char buf [1024], frag [128]; /*********/ /* begin */ /*********/ if (dbug>1) dbugThis (FI_LI, "renderParse()"); docptr->asis = docptr->insightAt = docptr->noescape = 0; memset (docptr->section, 0, sizeof(docptr->section)); for (idx = 0; idx < docptr->flagCount; idx++) free (docptr->flags[idx]); docptr->flagCount = 0; docptr->conditional[docptr->conLevel = 0] = 1; if (!(tptr = docptr->text)) RETURN_FI_LI (docptr, SS$_NOSUCHOBJECT) /* to be applied to the whole document it needs to be handled up-front */ for (cptr = tptr; *cptr && *cptr != '\n'; cptr++); while (*cptr == '\n') cptr++; if (MATCH12 (cptr, "|set|insight")) { error = renderSet (docptr, cptr+5); if (error) { SET_FI_LI (docptr); goto param_error; } } for (;;) { if (HMORE(docptr)) wasDocMoreHtml (docptr); if (!docptr->hlength) { sys$fao (&faoDsc, 0, &vtimeDsc, 0); error = wasDocPrintf (docptr, "<!DOCTYPE html>\n\ <!-- %s%s%s%s -->\n\ <!-- wasDOC Copyright (C) %s Mark G.Daniel - Apache-2.0 licenced -->\n\ <!-- %s -->\n\ <noscript>NOTE: SOME FUNCTIONALITY EMPLOYS JAVASCRIPT</noscript>\n\ <div id=\"erreport1\" style=\"display:none;\"></div>\n\ <script>\n\ function errorReport(string) {\n\ for (var cnt = 1; cnt <= 2; cnt++) {\n\ var err = document.getElementById(\'erreport\'+cnt);\n\ err.style.display = \'block\';\n\ err.innerHTML += string;\n\ }\n\ }\n\ </script>\n", SoftwareID, isCgi ? " CGI" : "", isCgiPlus ? "plus" : "", docptr->isDynamic ? " CLI" : "", CopyrightDate, vtime); if (docptr->errorValue) GOTO_FI_LI (docptr, insert_error) /* must follow the <!DOCTYPE..> */ if (docptr->insight >= 2) { wasDocInsight (docptr, "BEGIN"); if (docptr->insight >= 2) wasDocInsight (docptr, "%d/%d bytes", docptr->hlength, docptr->hsize); } } /* Th-th-th-that's all folks! */ if (!*tptr) break; if (docptr->conditional[docptr->conLevel] <= 0) { /******************/ /* not processing */ /******************/ while (*tptr) { while (*tptr && *tptr != '|') tptr++; if (!*tptr) break; if (MATCH4 (tptr, "|if|") || MATCH6 (tptr, "|elif|") || MATCH6 (tptr, "|else|") || MATCH7 (tptr, "|endif|")) { TPUT (docptr, tptr); error = renderCondition (docptr); if (error) GOTO_FI_LI (docptr, conditional_error) TGET (docptr, tptr); if (docptr->conditional[docptr->conLevel] > 0) break; } else if (MATCH7 (tptr, "|break|")) { wasDocAsIs (docptr, "\n<!-- $$BREAK$$ -->\n"); break; } else if (MATCH6 (tptr, "|exit|")) { wasDocAsIs (docptr, "\n<!-- $$EXIT$$ -->\n"); return (SS$_ABORT); } else tptr++; } continue; } if (!isspace(*tptr)) { if (!(*tptr == '|' && (MATCH5 (tptr, "|set|") || MATCH7 (tptr, "|style|")))) { /* provide default wasDOC style if not yet otherwise specified */ if (!docptr->styled) { renderStyle (docptr, NULL); continue; } } } if (docptr->asis) { /********/ /* asis */ /********/ /* as-is only terminated by \n||||\n (i.e 4 on a line by itself) */ while (*tptr) { if (HMORE(docptr)) wasDocMoreHtml (docptr); if (*tptr == '\n') { if (MATCH7 (tptr, "\n\\||||\n")) { /* seems obvious this is needed if to be documented :-) */ HONE (docptr, tptr); } else if (MATCH6 (tptr, "\n||||\n")) { if (docptr->insight >= 4) renderInsightTag (docptr); /* 1 is "standalone" while 2 is a <div> */ if (docptr->asis == 2) { if (docptr->stindex > 0) { if (MATCH4 (docptr->cstack[docptr->stindex], "||||")) { /* turn it into a <div> closure */ wasDocAsIs (docptr, "</div>"); docptr->stindex--; } } } tptr += 6; docptr->asis = 0; break; } } HONE (docptr, tptr); } continue; } if (docptr->noescape) { /******************/ /* no-HTML-escape */ /******************/ /* can only be terminated by || or |!"| */ while (*tptr) { if (HMORE(docptr)) wasDocMoreHtml (docptr); if (docptr->insight >= 2) if (MATCH4 (tptr, "\\<!-")) if (MATCH0 (tptr, "\\<!-- source:", 13)) renderInsightSource (docptr, tptr+13); if (*tptr == '\\') { if (MATCH2 (tptr, "\\\n")) { /* escaped newline - no newline at all */ tptr += 2; continue; } if (MATCH2 (tptr, "\\ ")) { /* escaped space */ tptr += 2; wasDocAsIs (docptr, " "); continue; } if (MATCH2 (tptr, "\\|")) { /* escaped bar */ tptr += 2; wasDocAsIs (docptr, "|"); continue; } if (MATCH4 (tptr, "\\\\\\\\")) { /* four consecutive backslashes just ignore */ tptr += 4; continue; } if (!MATCH2 (tptr, "\\\0")) { /* escape any other character */ tptr++; HONE (docptr, tptr); continue; } } if (MATCH2 (tptr, "||")) { /* 1 is "standalone" and 2 is a <span>/<div> */ if (docptr->noescape == 1) tptr += 2; docptr->noescape = 0; break; } if (MATCH4 (tptr, "|!\"|")) { /* ditto */ if (docptr->noescape == 1) tptr += 4; docptr->noescape = 0; break; } if (*tptr == '\n') { if (MATCH3 (tptr, "\n|\n")) { /* a non-breaking newline */ tptr += 2; } } HONE (docptr, tptr); } continue; } while (*tptr && *tptr != '|') { /***************/ /* HTML escape */ /***************/ if (HMORE(docptr)) wasDocMoreHtml (docptr); if (docptr->insight >= 2) if (MATCH4 (tptr, "\\<!-")) if (MATCH0 (tptr, "\\<!-- source:", 13)) renderInsightSource (docptr, tptr+13); if (*tptr == '<') { tptr++; wasDocAsIs (docptr, "<"); continue; } if (*tptr == '>') { tptr++; wasDocAsIs (docptr, ">"); continue; } if (*tptr == '&') { tptr++; wasDocAsIs (docptr, "&"); continue; } if (*tptr == '\"') { tptr++; wasDocAsIs (docptr, """); continue; } if (*tptr == '$') { /* wasDOC uses back-to-back $s for control sequences */ tptr++; wasDocAsIs (docptr, "$"); continue; } if (*tptr == '\\') { if (MATCH2 (tptr, "\\\n")) { /* escaped newline - no newline at all */ tptr += 2; continue; } if (MATCH2 (tptr, "\\ ")) { /* escaped space */ tptr += 2; wasDocAsIs (docptr, " "); continue; } if (MATCH2 (tptr, "\\|")) { /* escaped bar */ tptr += 2; wasDocAsIs (docptr, "|"); continue; } if (MATCH4 (tptr, "\\\\\\\\")) { /* four consecutive backslashes just ignore */ tptr += 4; continue; } if (!MATCH2 (tptr, "\\\0")) { /* escape any other character */ tptr++; HONE (docptr, tptr); continue; } } if (MATCH2 (tptr, "//") && *(tptr-1) == '\n') { /* line begins with // */ while (*tptr && *tptr != '\n') tptr++; while (*tptr && *tptr == '\n') tptr++; continue; } if (*tptr == '\n') { if (MATCH3 (tptr, "\n|\n")) { /* a non-breaking newline */ tptr += 2; } } HONE (docptr, tptr); } if (!*tptr) break; /*****************/ /* must be a '|' */ /*****************/ if (ENDTAG (tptr)) { /***************/ /* end element */ /***************/ tagptr = tptr; if (MATCH2 (tptr, "||")) tptr += 2; else if (MATCH2 (tptr, "|!")) { /* documented end */ if (isspace(*(tptr+2))) GOTO_FI_LI (docptr, BADPARAM_error) for (cptr = tptr + 2; *cptr && *cptr != '\n' && *cptr != '|'; cptr++); if (*cptr != '|') GOTO_FI_LI (docptr, BADPARAM_error) tptr = cptr + 1; } else tptr++; if (!docptr->stindex) GOTO_FI_LI (docptr, stack_uflow) aptr = docptr->cstack[docptr->stindex]; if (MATCH3 (aptr, "</h") && isdigit(aptr[3])) { wasDocAsIs (docptr, aptr); if (docptr->notable == NOTE_HEADING) { /* explicit heading has been provided so now in |note| text */ docptr->notable = NOTE_TEXT; wasDocAsIs (docptr, "\n<hr class=\"note_hr\">"); } } else if (MATCH8 (aptr, "</table>")) { if (docptr->table) docptr->table--; /* for the outermost table cancel any row highlight */ if (!docptr->table) docptr->rowlight = 0; wasDocAsIs (docptr, aptr); } else if (MATCH6 (aptr, "<-div>")) { /* faux tag; reset any flag and convert to a div closure */ if (!docptr->bfindex) GOTO_FI_LI (docptr, stack_uflow) docptr->bflag[docptr->bfindex--] = 0; wasDocAsIs (docptr, "</div>"); } else if (MATCH7 (aptr, "<-note>")) { /* faux tag similar in purpose to above */ if (!docptr->bfindex) GOTO_FI_LI (docptr, stack_uflow) docptr->notable = 0; docptr->bflag[docptr->bfindex--] = 0; wasDocAsIs (docptr, "<hr class=\"note_hr\">\n</div>"); } else if (aptr) wasDocAsIs (docptr, aptr); /* already checked the stack depth above */ docptr->stindex--; if (docptr->insight >= 4) renderInsightTag (docptr); continue; } /*****************/ /* special cases */ /*****************/ if (docptr->insight >= 4) if (MATCH5 (tptr, "|...|") || MATCH5 (tptr, "|:::|")) renderInsightTag (docptr); /* must be parsed before table |. */ if (MATCH5 (tptr, "|...|")) { tptr += 5; wasDocAsIs (docptr, "…"); continue; } if (MATCH5 (tptr, "|:::|")) { tptr += 5; wasDocAsIs (docptr, "⋮"); continue; } if (docptr->table) { /********************/ /* table processing */ /********************/ if (MATCH2 (tptr, "|~") || MATCH4 (tptr, "|row") || MATCH3 (tptr, "|tr")) { /*******/ /* row */ /*******/ /* table insight is messy! */ rowptr = tptr; /* compress intervening white-space */ cptr = renderTrimWhite (docptr); /* ensuring that empty elements work with CSS :empty */ if (!MATCH4 (cptr, "<tr ") && !MATCH4 (cptr, "<th ") && !MATCH4 (cptr, "<td ")) wasDocAsIs (docptr, "\n"); TPUT (docptr, tptr); error = renderInsertTag (docptr, "<tr"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; continue; } if (MATCH2 (tptr, "|:") || (MATCH3 (tptr, "|th") && ispunct(tptr[3])) || (MATCH3 (tptr, "|th") && isdigit(tptr[3])) || (MATCH5 (tptr, "|head") && ispunct(tptr[5])) || (MATCH5 (tptr, "|head") && isdigit(tptr[5]))) { /********/ /* head */ /********/ tagptr = tptr; /* compress intervening white-space */ cptr = renderTrimWhite (docptr); /* ensuring that empty elements work with CSS :empty */ if (!MATCH4 (cptr, "<tr ") && !MATCH4 (cptr, "<th ") && !MATCH4 (cptr, "<td ")) wasDocAsIs (docptr, "\n"); TPUT (docptr, tptr); error = renderInsertTag (docptr, "<th"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; /* absorb leading white-space */ while (*tptr && isspace(*tptr)) tptr++; if (docptr->insight >= 4) { /* table insight is messy! */ if (rowptr) { renderInsightTag (docptr); rowptr = NULL; } renderInsightTag (docptr); } continue; } if (MATCH2 (tptr, "|.") || (MATCH3 (tptr, "|td") && ispunct(tptr[3])) || (MATCH3 (tptr, "|td") && isdigit(tptr[3])) || (MATCH5 (tptr, "|data") && ispunct(tptr[5])) || (MATCH5 (tptr, "|data") && isdigit(tptr[5]))) { /********/ /* data */ /********/ tagptr = tptr; /* compress intervening white-space */ cptr = renderTrimWhite (docptr); /* ensuring that empty elements work with CSS :empty */ if (!MATCH4 (cptr, "<tr ") && !MATCH4 (cptr, "<th ") && !MATCH4 (cptr, "<td ")) wasDocAsIs (docptr, "\n"); TPUT (docptr, tptr); error = renderInsertTag (docptr, "<td"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; /* absorb leading white-space */ while (*tptr && isspace(*tptr)) tptr++; if (docptr->insight >= 4) { /* table insight is messy! */ if (rowptr) { renderInsightTag (docptr); rowptr = NULL; } renderInsightTag (docptr); } continue; } } else if (MATCH2 (tptr, "|~") || MATCH2 (tptr, "|:") || MATCH2 (tptr, "|.")) GOTO_FI_LI (docptr, outside_table_error) else if ((MATCH3 (tptr, "|tr") && ispunct(tptr[3])) || (MATCH4 (tptr, "|row") && ispunct(tptr[4]))) GOTO_FI_LI (docptr, outside_table_error) else if ((MATCH3 (tptr, "|th") && ispunct(tptr[3])) || (MATCH5 (tptr, "|head") && ispunct(tptr[5]))) GOTO_FI_LI (docptr, outside_table_error) else if ((MATCH3 (tptr, "|td") && ispunct(tptr[3])) || (MATCH5 (tptr, "|data") && ispunct(tptr[5]))) GOTO_FI_LI (docptr, outside_table_error) /* a few cycles could have been saved by stepping over the '|' */ /* just seemed to make the tags clearer in the code left in :-/ */ /*********/ /* other */ /*********/ if (docptr->insight >= 4) renderInsightTag (docptr); if (MATCH2 (tptr, "|\"")) { /* 1 is "standalone" and 2 is a <span>/<div> */ docptr->noescape = 1; tptr += 2; continue; } if (MATCH2 (tptr, "|\\")) { /* leading backslash; ignore the rest of the tag */ for (tptr++; *tptr; tptr++) { if (MATCH2 (tptr, "\\|")) tptr += 2; else if (*tptr == '|' && ENDTAG (tptr)) break; } if (!*tptr) break; if (MATCH2 (tptr, "||")) tptr++; tptr++; continue; } /* especially this one needs to be before "strike" */ if (MATCH3 (tptr, "|-|")) { tptr += 3; wasDocAsIs (docptr, "–"); continue; } if (MATCH4 (tptr, "|--|")) { tptr += 4; wasDocAsIs (docptr, "—"); continue; } if (MATCH3 (tptr, "|//")) { /* comment (must come before "|/" - italic) */ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = " -->"; wasDocAsIs (docptr, "<!-- "); tptr += 3; continue; } /*************/ /* list item */ /*************/ /* must precede the highlight equivalent */ if (MATCH2 (tptr, "|&") && isspace(tptr[2])) { tptr += 2; wasDocAsIs (docptr, "<li class=\"item\">"); continue; } /*************/ /* highlight */ /*************/ if (MATCH2 (tptr, "|*") || MATCH2 (tptr, "|-") || MATCH2 (tptr, "|_") || MATCH2 (tptr, "|=") || MATCH2 (tptr, "|\'") || /* single quote */ MATCH2 (tptr, "|/") || /* double quote */ MATCH2 (tptr, "|>") || MATCH2 (tptr, "|<") || MATCH2 (tptr, "|&")) { if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</span>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<span"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); continue; } /*********/ /* break */ /*********/ if (MATCH2 (tptr, "|^") && isspace(tptr[2])) { tptr += 2; wasDocAsIs (docptr, "<p>"); continue; } if (MATCH3 (tptr, "|^-")) { /* line */ tptr += 3; wasDocAsIs (docptr, "<br>"); continue; } if (MATCH3 (tptr, "|^+")) { tptr += 3; wasDocAsIs (docptr, "<p class=\"indent\">"); continue; } if (tptr[1] >= '0' && tptr[1] <= '9') { /***********/ /* heading */ /***********/ /* all tags should be closed before each major heading */ if (tptr[1] == '1' || MATCH2 (tptr+1, "01")) { if (docptr->conLevel > 0) GOTO_FI_LI (docptr, conditional_error) if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error) } /* if explicit heading for |note| */ if (docptr->notable == NOTE_BEGIN) if (tptr[1] == '0') docptr->notable = NOTE_HEADING; TPUT (docptr, tptr); error = renderInsertHeading (docptr); if (error == SS$_ITEMNOTFOUND) goto unknown_tag; if (error == SS$_RESULTOVF) goto stack_oflow; if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); continue; } /**********/ /* phrase */ /**********/ if (dbug>1) dbugThis (FI_LI, "%s %s", renderTag(tptr), renderLine(docptr)); if (MATCH6 (tptr, "|asis|")) { /* 1 is "standalone" and 2 is a <div> */ docptr->asis = 1; tptr += 6; if (*tptr == '\n') tptr++; continue; } if ((MATCH5 (tptr, "|asis") || MATCH6 (tptr, "|block") || MATCH5 (tptr, "|code") || MATCH8 (tptr, "|example") || MATCH7 (tptr, "|inline") || MATCH5 (tptr, "|mono") || MATCH5 (tptr, "|prop") || MATCH6 (tptr, "|quote")) && (ispunct(tptr[5]) || ispunct(tptr[6]) || ispunct(tptr[7]) || ispunct(tptr[8]))) { /*********/ /* block */ /*********/ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; cptr = "<div"; if (MATCH4 (tptr, "|asi")) { docptr->cstack[docptr->stindex] = "||||"; /* special case */ /* 1 is "standalone" and 2 is a <div> */ docptr->asis = 2; } else if (MATCH4 (tptr, "|inl")) { cptr = "<span"; docptr->cstack[docptr->stindex] = "</span>"; } else docptr->cstack[docptr->stindex] = "<-div>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, cptr); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; /* absorb any trailing newline (backslash escape if required) */ if (*tptr == '\n') tptr++; continue; } if (MATCH5 (tptr, "|note") && ispunct(tptr[5])) { /********/ /* note */ /********/ /* one at a time thank you */ if (docptr->notable) GOTO_FI_LI (docptr, BADPARAM_error) docptr->notable = NOTE_BEGIN; if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "<-note>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<div"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; /* scan ahead for an explicit note heading */ for (cptr = tptr; *cptr && isspace(*cptr); cptr++); if (!MATCH2 (cptr, "|0")) { /* doesn't look like it so provide default */ docptr->notable = NOTE_HEADING; error = renderInsertNote (docptr); if (error) { SET_FI_LI (docptr); goto param_error; } docptr->notable = NOTE_TEXT; } continue; } if (MATCH6 (tptr, "|table") || MATCH8 (tptr, "|tabular")) { /*********/ /* table */ /*********/ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</table>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<table"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; docptr->table++; continue; } if ((MATCH3 (tptr, "|ul") && ispunct(tptr[3])) || (MATCH7 (tptr, "|bullet") && ispunct(tptr[7]))) { /**********/ /* bullet */ /**********/ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</ul>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<ul"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; continue; } if ((MATCH3 (tptr, "|ol") && ispunct(tptr[3])) || (MATCH7 (tptr, "|number") && ispunct(tptr[7]))) { /**********/ /* number */ /**********/ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</ol>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<ol"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; continue; } if ((MATCH3 (tptr, "|sl") && ispunct(tptr[3])) || (MATCH7 (tptr, "|simple") && ispunct(tptr[7]))) { /**********/ /* simple */ /**********/ /* no bullets, no item numbers */ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</ul>"; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<sl"); /* faux tag */ if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; continue; } if ((MATCH3 (tptr, "|li") && ispunct(tptr[3])) || (MATCH5 (tptr, "|item") && ispunct(tptr[5]))) { TPUT (docptr, tptr); error = renderInsertTag (docptr, "<li"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; continue; } if (*(cptr = tptr + 1) == '%') cptr++; while (*cptr && cptr < tptr+8 && isalpha(*cptr)) cptr++; if (MATCH3 (cptr, "://") || (MATCH5 (tptr, "|link") && ispunct(tptr[5])) || MATCH8 (tptr, "|mailto:")) { /********/ /* link */ /********/ int image = 0, link, linkin = 0, target = 0; if (link = MATCH5 (tptr, "|link")) { target = (tptr[5] == '%'); for (cptr = tptr+5; *cptr && *cptr != '|'; cptr++); if (*cptr) cptr++; while (*cptr && *cptr != '|') cptr++; /* allow an image to be the link description */ image = MATCH6 (cptr, "|image") && ispunct(cptr[6]); } else if (target = (MATCH2(tptr,"|%"))) tptr += 2; if (link) { TPUT (docptr, tptr); if (image) error = renderInsertTag (docptr, "<aimg "); /* faux tag */ else error = renderInsertTag (docptr, "<a "); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); } else if (target) { if (image) wasDocAsIs (docptr, "<a class=\"link\" target=\"_blank\" href=\""); else wasDocAsIs (docptr, "<a class=\"link blank\" target=\"_blank\" href=\""); } else wasDocAsIs (docptr, "<a class=\"link\" href=\""); if (link) { /* get the URL (tag parameter) */ tptr++; TPUT (docptr, tptr); error = renderGetParam (docptr, buf, sizeof(buf)); if (error) { SET_FI_LI (docptr); goto param_error; } if (!buf[0]) GOTO_FI_LI (docptr, BADPARAM_error) TGET (docptr, tptr); /* ensure it only contains significant characters */ for (sptr = cptr = buf; *cptr; cptr++) if (iscntrl(*cptr)) *sptr++ = ' '; else *sptr++ = *cptr; *sptr = '\0'; /* check for "<URL>##<heading>++in++<document-title>" */ if (sptr = strstr (buf, "##")) { if (sptr = strstr (sptr+2, "++")) { if (strstr (sptr+2, "++")) { if (image) GOTO_FI_LI (docptr, BADPARAM_error) else { error = renderInsertLinkIn (docptr, buf, target); if (error) { SET_FI_LI (docptr); goto param_error; } if (MATCH2 (tptr, "||")) tptr++; if (*tptr) tptr++; continue; } } } } } else { /* else an explicit URL */ if (*tptr == '|') tptr++; for (zptr = (sptr = buf) + sizeof(buf)-1; *tptr && *tptr != '|' && sptr < zptr; tptr++) if (!iscntrl(*cptr) && !isspace(*tptr)) *sptr++ = *tptr; if (sptr == buf || sptr >= zptr) GOTO_FI_LI (docptr, BADPARAM_error); *sptr = '\0'; } error = renderInsertLink (docptr, buf); if (error) { SET_FI_LI (docptr); goto param_error; } wasDocAsIs (docptr, "\">"); if (image) { if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</a>"; continue; /*** NOTE ***/ } else if (ENDTAG (tptr)) { if (MATCH7 (buf, "mailto:")) /* reuse the URL as the link description */ wasDocAsIs (docptr, buf+7); else if (buf[0] == '/' || strstr (buf, "://")) /* reuse the URL as the link description */ wasDocAsIs (docptr, buf); else if (cptr = strstr (buf, "##")) /* use the free text hash as the description */ wasDocAsIs (docptr, cptr+2); /* else an empty description */ wasDocAsIs (docptr, "</a>"); } else { /* explicit description follows */ if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</a>"; } if (MATCH2 (tptr, "||")) tptr++; if (*tptr) tptr++; continue; } if (MATCH5 (tptr, "|draw") && ispunct(tptr[5])) { /********/ /* draw */ /********/ TPUT (docptr, tptr); error = renderInsertTag (docptr, "<div"); if (error) { SET_FI_LI (docptr); goto param_error; } error = drawThis (docptr); if (error) { SET_FI_LI (docptr); goto param_error; } wasDocAsIs (docptr, "</div>\n"); TGET (docptr, tptr); continue; } if (MATCH6 (tptr, "|image") && ispunct(tptr[6])) { /*********/ /* image */ /*********/ int linked, linked2; /* buffer the |image tptr */ aptr = tptr; /* begin spanning towards the URL */ for (tptr += 6; *tptr && *tptr != '|'; tptr++) if (*tptr == '%' || *tptr == '\'' || *tptr == '&') break; /* internal link cannot be used if the image is a link descriptor */ if (linked = (*tptr == '%')) { if (docptr->stindex > 0) if (MATCH4 (docptr->cstack[docptr->stindex], "</a>")) linked = 0; /* two indicate the link should open in a separate page */ if (linked) linked2 = MATCH2 (tptr, "%%"); } /* span to the start of the URL */ while (*tptr && *tptr != '|') tptr++; if (*tptr) tptr++; /* get the URL */ TPUT (docptr, tptr); error = renderGetParam (docptr, buf, sizeof(buf)); if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error) if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (linked) { if (linked2) wasDocAsIs (docptr, "<a class=\"imglink\" target=\"_blank\" href=\""); else wasDocAsIs (docptr, "<a class=\"imglink\" href=\""); error = renderInsertUrl (docptr, buf); if (error) { SET_FI_LI (docptr); goto param_error; } wasDocAsIs (docptr, "\">"); } /* use the original tptr that was buffered in aptr */ cptr = tptr; tptr = aptr; TPUT (docptr, tptr); error = renderInsertTag (docptr, "<img"); if (error) { SET_FI_LI (docptr); goto param_error; } error = renderInsertUrl (docptr, buf); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); wasDocAsIs (docptr, "\">"); /* go back to the tptr just beyond the URL parameter */ tptr = cptr; if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; if (linked) wasDocAsIs (docptr, "</a>"); else if (docptr->stindex > 0) if (MATCH4 (docptr->cstack[docptr->stindex], "</a>")) { /* the image is being used as the link */ docptr->stindex--; wasDocAsIs (docptr, "</a>"); } continue; } if (MATCH7 (tptr, "|insert") && ispunct(tptr[7])) { /**********/ /* insert */ /**********/ if (tptr[7] == '|') { tptr += 8; TPUT (docptr, tptr); error = renderGetParam (docptr, buf, sizeof(buf)); if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error) if (error) { SET_FI_LI (docptr); goto param_error; } error = renderInsertOther (docptr, buf); if (error) { SET_FI_LI (docptr); goto insert_error; } TGET (docptr, tptr); } else { TPUT (docptr, tptr); error = renderInsertTag (docptr, "<span"); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; TPUT (docptr, tptr); error = renderGetParam (docptr, buf, sizeof(buf)); if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error) if (error) { SET_FI_LI (docptr); goto param_error; } error = renderInsertOther (docptr, buf); if (error) { SET_FI_LI (docptr); goto insert_error; } TGET (docptr, tptr); wasDocAsIs (docptr, "</span>"); } if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; continue; } /**************/ /* conditions */ /**************/ if (MATCH4 (tptr, "|if|") || MATCH6 (tptr, "|elif|") || MATCH6 (tptr, "|else|") || MATCH7 (tptr, "|endif|")) { TPUT (docptr, tptr); error = renderCondition (docptr); if (error) { SET_FI_LI (docptr); goto conditional_error; } TGET (docptr, tptr); continue; } /**********/ /* others */ /**********/ if (MATCH5 (tptr, "|set|")) { tptr += 5; TPUT (docptr, tptr); error = renderGetParam (docptr, buf, sizeof(buf)); if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error) if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); error = renderSet (docptr, buf); if (error) { SET_FI_LI (docptr); goto param_error; } if (MATCH2 (tptr, "||")) tptr++; if (*++tptr == '\n') tptr++; continue; } if (MATCH7 (tptr, "|style|")) { tptr += 7; TPUT (docptr, tptr); error = renderGetParam (docptr, buf, sizeof(buf)); if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error) if (error) { SET_FI_LI (docptr); goto param_error; } error = renderStyle (docptr, buf); if (error) { SET_FI_LI (docptr); goto param_error; } TGET (docptr, tptr); if (MATCH2 (tptr, "||")) tptr++; if (*tptr) tptr++; continue; } if (MATCH7 (tptr, "|print|")) { if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</div>"; wasDocAsIs (docptr, "<div class=\"print\">"); tptr += 7; if (*tptr == '\n') tptr++; continue; } if (MATCH9 (tptr, "|noprint|")) { if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow) docptr->tstack[docptr->stindex] = tptr; docptr->cstack[docptr->stindex] = "</div>"; wasDocAsIs (docptr, "<div class=\"noprint\">"); tptr += 9; if (*tptr == '\n') tptr++; continue; } if (MATCH6 (tptr, "|ppage|")) { /* at a page break all tags should have been closed */ if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error) wasDocAsIs (docptr, "<hr class=\"ppage\">"); tptr += 6; if (*tptr == '\n') tptr++; continue; } if (MATCH5 (tptr, "|toc|")) { /* insert a marker for where the TOC will be */ tptr += 5; if (MATCH2 (tptr, "||")) tptr++; tptr++; wasDocAsIs (docptr, "<!--$$TOC$$-->"); continue; } if (MATCH7 (tptr, "|index|")) { /* insert a marker for where the INDEX will be */ tptr += 7; if (MATCH2 (tptr, "||")) tptr++; tptr++; wasDocAsIs (docptr, "<!--$$IDX$$-->"); continue; } if (MATCH7 (tptr, "|break|")) { wasDocAsIs (docptr, "\n<!-- $$BREAK$$ -->\n"); TPUT (docptr, tptr); break; } if (MATCH6 (tptr, "|exit|")) { wasDocAsIs (docptr, "\n<!-- $$EXIT$$ -->\n"); TPUT (docptr, tptr); return (SS$_ABORT); } if (MATCH10 (tptr, "|insight!|")) { tptr += 10; TPUT (docptr, tptr); renderInsightStack (docptr); TGET (docptr, tptr); continue; } if (MATCH10 (tptr, "|insight@|")) { tptr += 10; if (docptr->isDynamic && docptr->insight) { wasDocAsIs (docptr, "<div class=\"noprint\">\n\ <input type=\"button\" onclick=\"button(\'text\')\" value=\"TEXT\">\n\ <input type=\"button\" onclick=\"button(\'html\')\" value=\"HTML\">\n\ <span id=\"lookstats\"></span>\n\ </div>\n"); docptr->insightAt = 1; } continue; } /***********/ /* unknown */ /***********/ GOTO_FI_LI (docptr, unknown_tag) } /*******/ /* end */ /*******/ if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error) if (pass2 (docptr) < 0) { TPUT (docptr, tptr); if (docptr->errorValue == SS$_NOSUCHOBJECT) renderErrorReport (docptr, "\n<div class=\"error\">Link target %s not found</div>\n", docptr->pass2At); else { cptr = strdup (strerror(EVMSERR,docptr->errorValue)); *cptr = toupper(*cptr); renderErrorReport (docptr, "\n<div class=\"error\">%s %s</div>\n", cptr, docptr->pass2At); free (cptr); } renderErrorReport (docptr, NULL); return (docptr->errorValue); } if (docptr->insight >= 2) wasDocInsight (docptr, "END"); return (0); post_condition_error: aptr = docptr->html + docptr->hparse; TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">%s post processing error <i>%s</i> \ at "<kbd>%s</kbd>" %s</div>\n", cptr, strerror(EVMSERR,error), renderLineEscape(aptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); unknown_tag: TPUT (docptr, tptr); renderErrorReport (docptr, "<div class=\"error\">Unknown tag "<kbd>%s</kbd>" at \ "<kbd>%s</kbd>" %s</div>\n", renderTag(tptr), renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); insert_error: TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">Insert failed <i>%s</i> at \ "<kbd>%s</kbd>" %s</div>\n", strerror(EVMSERR,error), renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); BADPARAM_error: error = SS$_BADPARAM; goto param_error; param_error: TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">Parameter error <i>%s</i> at \ \"<kbd>%s</kbd>\" %s</div>\n", strerror(EVMSERR,error), renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); vms_status_error: TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">VMS status %%X%08.08X error <i>%s</i> at \ \"<kbd>%s</kbd>\" %s</div>\n", error, strerror(EVMSERR,error), renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); outside_table_error: TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">Tag "<kbd>%s</kbd>" used outside table at \ "<kbd>%s</kbd>" %s</div>\n", renderTag(tptr), renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); stack_oflow: TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">Overflow at "<kbd>%s</kbd>"%s</div>\n", renderLine(docptr)); renderErrorReport (docptr, NULL); return (error); stack_uflow: TPUT (docptr, tptr); renderErrorReport (docptr, "\n<div class=\"error\">Underflow at "<kbd>%s</kbd>" %s</div>\n", renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); conditional_error: if (!error) cptr = "unbalanced"; else cptr = strerror(EVMSERR,error); TPUT (docptr, tptr); renderErrorReport (docptr, "<div class=\"error\">Conditional <i>%s</i> at \ "<kbd>%s</kbd>" %s</div>", cptr, renderLine(docptr), renderSource(docptr)); renderErrorReport (docptr, NULL); return (error); unbalanced_error: TPUT (docptr, tptr); renderErrorReport (docptr, "<div class=\"error\">Unbalanced at "<kbd>%s</kbd>" %s", renderLine(docptr), renderSource(docptr)); while (docptr->stindex) { renderErrorReport (docptr, "<br>%d "<kbd>%s</kbd>"", docptr->stindex, renderLine(docptr)); docptr->stindex--; } renderErrorReport (docptr, "</div>"); renderErrorReport (docptr, NULL); return (error); } /*****************************************************************************/ /* If the primary document reports an error in some indeterminate state (e.g. inside a heading, monospace, italic, table, etc.) to get the error report out a markup-clean environment is needed. Hence the IFRAME. The iframe is populated using JavaScript. An initial call sets up the dynamic created IFRAME and formats an initial report line. Subsequent calls can add lines to the report. A final "cleanup" call (mandatory) loses and displays the report. */ int renderErrorReport ( struct wasdoc_st *docptr, char *fmt, ... ) { static int init = 0; int cnt, linum, retval, size; char *aptr, *bptr, *fiptr, *cptr, *sptr, *tptr, *zptr; char finame [64]; va_list args; if (dbug>2) dbugThis (FI_LI, "renderErrorReport() %s", dbugMax(fmt)); if (!fmt) { /* end call */ wasDocPrintf (docptr, "</script>\n"); init = 0; return (0); } va_start (args, fmt); size = vsnprintf (NULL, 0, fmt, args); va_end (args); if (size < 0) return (vaxc$errno); bptr = calloc (1, size); if (!bptr) exit (vaxc$errno); va_start (args, fmt); retval = vsprintf (bptr, fmt, args); va_end (args); if (retval < 0) return (retval); if (retval != size) wasDocBugcheck(FI_LI); /* escape any forbiddens in the string */ cnt = 0; for (cptr = bptr; *cptr; cptr++) if (*cptr == '\n' || *cptr == '\'' || *cptr == '\\') cnt++; if (cnt) { aptr = sptr = calloc (1, size + cnt); if (!aptr) exit (vaxc$errno); for (cptr = bptr; *cptr; cptr++) { if (*cptr == '\n' || *cptr == '\'' || *cptr == '\\') *sptr++ = '\\'; if (*cptr == '\n') *sptr++ = 'n'; else if (isprint(*cptr)) *sptr++ = *cptr; } free (bptr); bptr = aptr; } if (!init) { if (fiptr = docptr->fiptr) { while (*fiptr) fiptr++; while (*(fiptr-1) != ']' && fiptr > docptr->fiptr) fiptr--; zptr = (sptr = finame) + sizeof(finame)-1; while (*fiptr && *fiptr != ';' && sptr < zptr) *sptr++ = *fiptr++; *sptr = '\0'; } linum = docptr->linum; wasDocPrintf (docptr, "<!-- FILE:%s LINE:%d -->", fiptr ? finame : "(null)", linum); } wasDocPrintf (docptr, "\n<div id=\"erreport2\" style=\"display:none;\"></div>\n\ <script>errorReport(\'%s\')</script>\n", bptr); init = 1; free (bptr); return (0); } /*****************************************************************************/ /* Return a pointer to the tag as a string. */ char* renderTag (char *tptr) { static char buf [32+3]; char *sptr, *zptr; if (dbug>2) dbugThis (FI_LI, "renderTag() %s", dbugMax(tptr)); zptr = (sptr = buf) + sizeof(buf)-3; *sptr++ = bvbar; if (*tptr == '|') *sptr++ = *tptr++; if (isalpha(*tptr)) { while (*tptr && *tptr != '|' && sptr < zptr) *sptr++ = *tptr++; *sptr++ = '|'; } else if (isdigit(*tptr)) while (*tptr && isdigit(*tptr)&& sptr < zptr) *sptr++ = *tptr++; else *sptr++ = *tptr; *sptr++ = bvbar; *sptr = '\0'; return (buf); } /*****************************************************************************/ /* Return a pointer to the line as a string. Call pointing at start of line. */ char* renderLine (struct wasdoc_st *docptr) { static char buf [96]; char *cptr, *sptr, *zptr; if (dbug>2) dbugThis (FI_LI, "renderLine() %s", dbugMax(docptr->text+docptr->tparse)); zptr = (sptr = buf) + sizeof(buf)-1; cptr = docptr->text + docptr->tparse; while (*cptr && *cptr != '\n') cptr++; while (*cptr == '\n') cptr++; while (cptr > docptr->text && *(cptr-1) == '\n') cptr--; while (cptr > docptr->text && *(cptr-1) != '\n') cptr--; while (*cptr && *cptr != '\n' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; cptr = dbugAll (buf); if (dbug>2) dbugThis (FI_LI, "%s", cptr); return (cptr); } /*****************************************************************************/ /* Return a pointer to a buffer containing the line number and source file name (see ConditionFile()). */ char* renderSource (struct wasdoc_st *docptr) { static char buf [128]; int clnum = 1, slnum = 0; char *cptr, *sptr, *tptr, *tzptr, *zptr; char sname [96]; strcpy (buf, "BUGCHECK!"); strcpy (sname, "BUGCHECK!"); tzptr = docptr->text + docptr->tparse; for (tptr = docptr->text; *tptr && tptr < tzptr; tptr++) { if (*tptr == '\n') clnum++; if (*tptr != '\\') continue; if (!MATCH4 (tptr, "\\<!-")) continue; if (!MATCH0 (tptr, "\\<!-- source:", 13)) continue; tptr += 13; slnum = clnum; zptr = (sptr = sname) + sizeof(sname)-1; while (*tptr && sptr < zptr && !isspace(*tptr)) *sptr++ = *tptr++; *sptr = '\0'; } sprintf (buf, "line %d in %s", clnum - slnum, sname); return (buf); } /*****************************************************************************/ /* Return a pointer to the line as a string. Escape HTML-forbiddens. Call pointing at start of line. */ char* renderLineEscape (char *hptr) { static char buf [96*3]; char *cptr, *sptr, *zptr; if (!hptr) hptr = "^0"; if (!*hptr) hptr = "^Z"; while (*hptr && *hptr == ' ') hptr++; zptr = (sptr = buf) + sizeof(buf)-1; while (*hptr && *hptr != '\n' && sptr < zptr) { switch (*hptr) { case '<' : for (cptr = "<"; *cptr && sptr < zptr; *sptr++ = *cptr++); break; case '>' : for (cptr = ">"; *cptr && sptr < zptr; *sptr++ = *cptr++); break; case '&' : for (cptr = "&"; *cptr && sptr < zptr; *sptr++ = *cptr++); break; default: *sptr++ = *hptr; } hptr++; } *sptr = '\0'; return (buf); } /*****************************************************************************/ /* Evaluate the conditional depending on the current conditioning status. Returns ECHILD on underflow, E2BIG on overflow, and SS$_BADPARAM if unknown. The docptr->conditional datum has the value 1) when processing -1) has processed but hit |elif| or |else| and so no longer 0) not processing Document content is only processed when it has a value > 0. So if an |elif| hits a 1 at its own level then that level goes to -1. Same for an |else|. The condition processor parses all levels in nested conditionals, even when not actually processing more nested levels due to non-processing less nested levels, and so should catch and report syntactic errors of all levels. */ int renderCondition (struct wasdoc_st *docptr) { int error = 0, elif = 0, insight, isnot = 0, minus1, yes = 0; char *aptr, *bptr, *cptr, *tptr; char buf [1024]; TGET (docptr, tptr); if (dbug>1) dbugThis (FI_LI, "renderCondition() %d %d %s", docptr->conLevel, docptr->conditional[docptr->conLevel], dbugMax(tptr)); /* some processing determined by the preceding level */ if (docptr->conLevel) minus1 = docptr->conditional[docptr->conLevel-1]; else minus1 = 1; /* if deeper not processing then no insight unless 5 or more */ insight = docptr->insight; if (minus1 <= 0) if (docptr->insight < 5) docptr->insight = 0; if ((elif = MATCH6 (tptr, "|elif|")) && !docptr->conLevel) error = ECHILD; else if (MATCH4 (tptr, "|if|") || elif) { tptr += 3; if (elif) tptr += 2; if (ENDTAG(tptr)) buf[0] = '\0'; else { tptr++; TPUT (docptr, tptr); renderGetParam (docptr, buf, sizeof(buf)); TGET (docptr, tptr); } if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; if (docptr->insight >= 4) wasDocInsight (docptr, "%s", buf); bptr = buf; if (*bptr == '!') { isnot = 1; bptr++; } else if (MATCH2 (bptr, "\\!")) bptr++; if (!bptr[0]) /* no conditional is false */ yes = 0; else if (MATCH2 (bptr, "0")) yes = 0; else if (MATCH2 (bptr, "1")) yes = 1; else if (MATCH8 (bptr, "dynamic")) yes = docptr->isDynamic; else if (MATCH7 (bptr, "static")) yes = docptr->isStatic; else if (MATCH7 (bptr, "single")) yes = !docptr->chunked; else if (MATCH6 (bptr, "multi")) yes = docptr->chunked; else if (MATCH5 (bptr, "hide")) yes = CgiLibVarNull("WWW_FORM_NOHIDE") != NULL; else if (MATCH5 (bptr, "wasd")) yes = CgiLibEnvironmentIsWasd(); else if (MATCH7 (bptr, "apache")) yes = CgiLibEnvironmentIsApache(); else if (MATCH4 (bptr, "osu")) yes = CgiLibEnvironmentIsOsu(); else if (MATCH4 (bptr, "cgi=")) { if (isCgi || isCgiPlus) { /* <cgi-name>[:<keyword><regex>] */ for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++); if (*aptr) *aptr++ = '\0'; cptr = CgiLibVarNull (bptr+4); yes = testCondition (docptr, cptr, aptr); } else yes = 0; } else if (MATCH4 (bptr, "lnm=")) { /* <log-name>[;<log-table>][:<keyword><regex>] */ for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++); if (*aptr) *aptr++ = '\0'; cptr = renderTrnLnm (docptr, bptr+7, 0); yes = testCondition (docptr, cptr, aptr); } else if (MATCH6 (bptr, "spawn=")) { /* spawn=<command>[:<keyword><regex>] */ for (aptr = cptr = bptr + 6; *aptr && *aptr != ':'; aptr++) { /* escape to allow ':' in the spawn command */ if (*aptr == '\\' && *(aptr+1) == ':') aptr++; *cptr++ = *aptr; } if (*aptr) *aptr++ = '\0'; *cptr = '\0'; yes = SpawnCommand (docptr, bptr+6, aptr) < 0; } else if (MATCH4 (bptr, "syi=")) { if (isCgi || isCgiPlus) { /* <SYI-name>[:<keyword><regex>] */ for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++); if (*aptr) *aptr++ = '\0'; cptr = renderGetSyi (docptr, bptr+4); yes = testCondition (docptr, cptr, aptr); } else yes = 0; } else if (MATCH5 (bptr, "time:")) yes = testTime (docptr, bptr+5); else if (MATCH8 (bptr, "insight:")) { /* is insight enabled is it at this value */ if (isdigit(bptr[8])) yes = atoi(bptr+8) >= docptr->insight; else yes = docptr->insight > 0; } else if (isupper(bptr[0])) { /* <FLAG>[:<keyword><regex>] */ for (aptr = bptr; *aptr && *aptr != ':'; aptr++); if (*aptr) *aptr++ = '\0'; cptr = renderFlag (docptr, bptr, 0); if (cptr) { if (*aptr) yes = testCondition (docptr, cptr, aptr); else { while (cptr && isspace(*cptr)) cptr++; if (isdigit(*cptr)) yes = atoi(cptr); else yes = !*cptr; } } else error = SS$_BADPARAM; } else error = SS$_BADPARAM; if (!error) { if (minus1 > 0) { /* deeper is processing */ if (isnot) yes = !yes; if (elif) if (docptr->conditional[docptr->conLevel] == 0) docptr->conditional[docptr->conLevel] = yes; else docptr->conditional[docptr->conLevel] = -1; else if (docptr->conditional[docptr->conLevel] > 0) if (docptr->conLevel < CONDITION_MAX) docptr->conditional[++docptr->conLevel] = yes; else error = E2BIG; else docptr->conditional[++docptr->conLevel] = -1; } else { /* deeper is NOT processing */ if (elif) docptr->conditional[docptr->conLevel] = -1; else if (docptr->conLevel < CONDITION_MAX) docptr->conditional[++docptr->conLevel] = -1; else error = E2BIG; } } } else if (MATCH6 (tptr, "|else|")) { if (docptr->insight >= 4) wasDocInsight (docptr, "|else|"); if (!docptr->conLevel) error = ECHILD; else if (minus1 > 0) /* deeper is processing */ if (docptr->conditional[docptr->conLevel] == 0) docptr->conditional[docptr->conLevel] = 1; else docptr->conditional[docptr->conLevel] = -1; else /* deeper is NOT processing */ docptr->conditional[docptr->conLevel] = -1; tptr += 6; } else if (MATCH7 (tptr, "|endif|")) { if (docptr->insight >= 4) wasDocInsight (docptr, "|endif|"); if (!docptr->conLevel) error = ECHILD; else docptr->conditional[docptr->conLevel--] = 0; tptr += 7; } else error = SS$_BADPARAM; if (docptr->insight >= 4) wasDocInsight (docptr, "%s%d/%d", docptr->conditional[docptr->conLevel] > 0 ? "✓" : "✗", docptr->conLevel, docptr->conditional[docptr->conLevel]); if (*tptr == '\n') tptr++; TPUT (docptr, tptr); docptr->insight = insight; if (dbug>1) dbugThis (FI_LI, "%d %d %s", docptr->conLevel, docptr->conditional[docptr->conLevel], dbugMax(tptr)); return (error); } /*****************************************************************************/ /* Copy a bar-delimited string into the supplied buffer. Return 0 for success or any other vaxc%errno for error. */ int renderGetParam ( struct wasdoc_st *docptr, char *buf, int size ) { char *sptr, *tptr, *zptr; TGET (docptr, tptr); if (dbug>1) dbugThis (FI_LI, "renderGetParam() %s", dbugMax(tptr)); if (size) buf[0] = '\0'; /* look slightly behind to check if one might not be supplied */ if (ENDTAG (tptr-1) && !MATCH2 (tptr-1, "|!")) return (0); zptr = (sptr = buf) + size - 1; if (zptr <= sptr) RETURN_FI_LI (docptr, SS$_RESULTOVF) while (*tptr && *tptr != '|' && sptr < zptr) { if (*tptr == '\\') { tptr++; if (*tptr == '\n') { tptr++; continue; } if (!*tptr) break; } *sptr++ = *tptr++; } if (*tptr != '|') RETURN_FI_LI (docptr, SS$_BADPARAM) if (sptr >= zptr) RETURN_FI_LI (docptr, SS$_RESULTOVF) *sptr = '\0'; TPUT (docptr, tptr); return (0); } /*****************************************************************************/ /* Set document characteristic. */ int renderSet ( struct wasdoc_st *docptr, char *param ) { int error = 0, number; char *cptr, *sptr, *tptr, *zptr; if (dbug>1) dbugThis (FI_LI, "renderSet() %s", dbugMax(param)); if (MATCH8 (param, "chunked=")) { /* 1 enables, 0 let the client decide, -1 disables */ int chunked; chunked = atoi(param+8); if (chunked < 0 || !docptr->chunked) docptr->chunked = chunked; } else if (MATCH6 (param, "found=")) { /* explicitly set the default of 'this "in" that' */ zptr = (sptr = docptr->setFoundIn) + sizeof(docptr->setFoundIn)-1; for (cptr = param + 6; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; } else if (MATCH9 (param, "idx=cols=")) { /* number of columns in the index */ number = atoi(param+9); if (number == 1 || number == 2 || number == 3 || number == 4) docptr->setIdxCols = number; else error = SS$_BADPARAM; } else if (MATCH9 (param, "idx=sort=")) { /* index entries sorted is 1, unsorted is 0 */ docptr->setIdxSort = atoi(param+9); } else if (MATCH12 (param, "idx=collate=")) { /* collation characters for index (26 Latin alphabetics default) */ zptr = (sptr = docptr->idxCollate) + sizeof(docptr->idxCollate)-1; /* if plus then append to existing collation, otherwise replace */ cptr = param + 12; if (*cptr == '+') { for (sptr = docptr->idxCollate; *sptr; sptr++); cptr++; } while (*cptr && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; } else if (MATCH8 (param, "insight=")) { /* is explicitly looked for *very* early in document processing */ if (docptr->insight = atoi(param+8)) if (cptr = CgiLibVarNull ("FORM_INSIGHT")) docptr->insight = atoi(cptr); } else if (MATCH7 (param, "locale=")) { if (MATCH0 (param, "locale=ctype=", 13)) { if (!setlocale (LC_CTYPE, param+13)) error = vaxc$errno; } else if (MATCH7 (param, "locale=") && isdigit(param[7]) && param[8] == '=') { if (!setlocale (atoi(param+8), param+10)) error = vaxc$errno; } else if (MATCH7 (param, "locale=")) { if (!setlocale (LC_ALL, param+7)) error = vaxc$errno; } } else if (MATCH9 (param, "navigate=")) { /* leading integer can enable/disable navigation icons */ cptr = param + 9; if (isdigit(*cptr)) { docptr->setNavigate = atoi(cptr); while (isdigit(*cptr)) cptr++; if (*cptr == '|') cptr++; } if (!*cptr) return (0); /* navigation icons, <back>|<prev>|<top>|<next>|<forward> */ if (*cptr != '|') { zptr = (sptr = docptr->iconBack) + sizeof(docptr->iconBack)-1; while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; while (*cptr && *cptr != '|') cptr++; } if (*cptr) cptr++; if (*cptr != '|') { zptr = (sptr = docptr->iconPrev) + sizeof(docptr->iconPrev)-1; while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; while (*cptr && *cptr != '|') cptr++; } if (*cptr) cptr++; if (*cptr != '|') { zptr = (sptr = docptr->iconTop) + sizeof(docptr->iconTop)-1; while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; while (*cptr && *cptr != '|') cptr++; } if (*cptr) cptr++; if (*cptr != '|') { zptr = (sptr = docptr->iconNext) + sizeof(docptr->iconNext)-1; while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; while (*cptr && *cptr != '|') cptr++; } if (*cptr) cptr++; if (*cptr != '|') { zptr = (sptr = docptr->iconForw) + sizeof(docptr->iconForw)-1; while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; while (*cptr && *cptr != '|') cptr++; } } else if (MATCH5 (param, "note=")) { /* explicitly set the default title of a note */ zptr = (sptr = docptr->setNote) + sizeof(docptr->setNote)-1; for (cptr = param + 5; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; } else if (MATCH9 (param, "paginate=")) { /* enable automatic pagination */ docptr->setPaginate = atoi(param+9); } else if (MATCH10 (param, "table=margin=")) { /* table margin (+, -, \0) */ docptr->setTabMargin = param[13]; docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER; } else if (MATCH6 (param, "title=")) { /* explicitly set the title of the document */ zptr = (sptr = docptr->title) + sizeof(docptr->title)-1; for (cptr = param + 6; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; } else if (MATCH12 (param, "toc2=next=cols=")) { /* number of columns in NEXT secondary table of content */ number = atoi(cptr = param+15); if (number == 1 || number == 2 || number == 3 || number == 4) /* propagate into second pass */ wasDocPrintf (docptr, "<!--$$X:%s$$-->", param); else error = SS$_BADPARAM; } else if (MATCH10 (param, "toc2=cols=")) { /* number of columns in secondary table of content */ number = atoi(cptr = param+10); if (number == 1 || number == 2 || number == 3 || number == 4) { docptr->setToc2Cols = number; while (*cptr && isdigit(*cptr)) cptr++; while (*cptr && !isdigit(*cptr)) cptr++; if (isdigit(*cptr)) if ((number = atoi(cptr)) <= 100) docptr->setToc2ColsWidth = number; } else error = SS$_BADPARAM; } else if (MATCH5 (param, "toc2=")) { /* whether a secondary TOC is generated */ cptr = param+5; if (isdigit(*cptr)) docptr->setToc2 = atoi(param+5); else error = SS$_BADPARAM; } else if (MATCH9 (param, "toc=cols=")) { /* number of colmns in table of content */ number = atoi(param+9); if (number == 1 || number == 2 || number == 3 || number == 4) docptr->setTocCols = number; else error = SS$_BADPARAM; } else if (MATCH11 (param, "toc=format=")) { /* explicitly set the format of the TOC */ zptr = (sptr = docptr->setTocForm) + sizeof(docptr->setTocForm)-1; for (cptr = param + 11; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; } else if (isupper (param[0])) { /* setting a flag */ if (!renderFlag (docptr, param, 1)) error = SS$_BADPARAM; } else error = SS$_BADPARAM; return (error); } /*****************************************************************************/ /* Flags begin with an upper-case alphabetic, have all upper-case alphabetics and digits. Flag strings are |set|FLAG[=<integer>|<string>]| by renderSet(). Search the array of flags strings for the specified flag. Can set a new flag, reset an existing flag, and also just search for a flag. If the parameter contains an equate symbol (=) then it's considered to be a (re)set. A set/reset returns a pointer for success or a NULL if something failed. If not found return NULL to indicate that. If found and if the flag has a value return a pointer to that (even if empty). */ char* renderFlag ( struct wasdoc_st *docptr, char *flag, int set ) { int idx; char *cptr, *sptr; if (dbug>1) dbugThis (FI_LI, "renderFlag() %d %s", set, dbugAll(flag)); /* search for an existing flag */ for (idx = 0; idx < docptr->flagCount; idx++) { sptr = flag; for (cptr = docptr->flags[idx]; *cptr && *cptr != '=' && *sptr && *sptr != '='; cptr++, sptr++) if (*cptr != *sptr) break; if (*cptr && *cptr != '=') continue; if (*sptr && *sptr != '=') continue; break; } if (idx >= docptr->flagCount) { /* not found */ if (!set) return (NULL); /* check not an empty name and is all upper */ for (cptr = flag; *cptr && *cptr != '=' && (isupper(*cptr) || isdigit(*cptr)); cptr++); if (cptr == flag) return (NULL); if (*cptr && *cptr != '=' && !isupper(*cptr) && !isdigit(*cptr)) return (NULL); /* set a new flag */ if (docptr->flagCount >= FLAG_MAX) RETURN_FI_LI (docptr, NULL) docptr->flags[docptr->flagCount] = calloc (strlen(flag), 1); if (!docptr->flags[docptr->flagCount]) RETURN_FI_LI (docptr, NULL) strcpy (docptr->flags[docptr->flagCount], flag); docptr->flagCount++; for (cptr = flag; *cptr && *cptr != '='; cptr++); if (*cptr) cptr++; return (cptr); } /* if reset an existing flag */ if (*sptr) { free (docptr->flags[idx]); docptr->flags[idx] = calloc (strlen(flag), 1); if (!docptr->flags[idx]) RETURN_FI_LI (docptr, NULL) strcpy (docptr->flags[idx], flag); for (cptr = flag; *cptr && *cptr != '='; cptr++); if (*cptr) cptr++; return (cptr); } /* if just searching for a flag */ if (*cptr) cptr++; return (cptr); } /*****************************************************************************/ /* The |1..|4 represent the primary TOC hierarchy. |0 represents a secondary heading without a primary TOC. |0 is transformed into an <h5> heading. Cross-reference |9 into a <h6>. Prefixing any section digit (01, 02, 03, 04) with a zero represents a heading without a primary TOC entry. */ int renderInsertHeading (struct wasdoc_st *docptr) { int error = 0; char nine9, zero0, zero1, zero2, zero3, zero4, zero9; char *cptr, *tptr; if (dbug>1) dbugThis (FI_LI, "renderInsertHeading()"); TGET (docptr, tptr); if (tptr[0] != '|') RETURN_FI_LI (docptr, SS$_FORMAT) if (docptr->stindex >= STACK_MAX) RETURN_FI_LI (docptr, SS$_RESULTOVF) docptr->tstack[++docptr->stindex] = tptr; /* leading zero suppresses primary TOC entry */ cptr = tptr + 1; /* bit sloppy and inefficient but */ zero0 = MATCH2(cptr, "00"); zero1 = MATCH2(cptr, "01"); zero2 = MATCH2(cptr, "02"); zero3 = MATCH2(cptr, "03"); zero4 = MATCH2(cptr, "04"); zero9 = MATCH2(cptr, "09"); nine9 = MATCH2(cptr, "99"); if (isdigit(*cptr) && isdigit(*(cptr+1))) cptr++; /* first visible heading becomes top of document */ if (*cptr >= '0' && *cptr <= '4') if (!(docptr->section[1] || docptr->section[2] || docptr->section[3] || docptr->section[4] || docptr->section[5])) wasDocAsIs (docptr, "<a id=\"0.\" href=\"#\"></a>\n"); switch (*cptr) { case '0' : if (zero0) docptr->section[5] = SECTION_NOT_IN; else docptr->section[5]++; docptr->section[6] = 0; docptr->cstack[docptr->stindex] = "</h5>"; cptr = "<h5"; break; case '1' : if (zero1) docptr->section[5]++; else { docptr->section[1]++; docptr->chunkTotal++; docptr->section[2] = docptr->section[3] = docptr->section[4] = docptr->section[5] = docptr->section[6] = 0; } docptr->cstack[docptr->stindex] = "</h1>"; cptr = "<h1"; break; case '2' : if (zero2) docptr->section[5]++; else { docptr->section[2]++; docptr->section[3] = docptr->section[4] = docptr->section[5] = docptr->section[6] = 0; } docptr->cstack[docptr->stindex] = "</h2>"; cptr = "<h2"; break; case '3' : if (zero3) docptr->section[5]++; else { docptr->section[3]++; docptr->section[4] = docptr->section[5] = docptr->section[6] = 0; } docptr->cstack[docptr->stindex] = "</h3>"; cptr = "<h3"; break; case '4' : if (zero4) docptr->section[5]++; else { docptr->section[4]++; docptr->section[5] = docptr->section[6] = 0; } docptr->cstack[docptr->stindex] = "</h4>"; cptr = "<h4"; break; case '5' : case '6' : case '7' : case '8' : case '9' : if (zero0) docptr->section[6] = SECTION_NO_INDEX; else if (nine9) docptr->section[6] = SECTION_NOT_IN; else docptr->section[6]++; docptr->cstack[docptr->stindex] = "</h6>"; cptr = "<h9"; /* faux tag */ break; default : RETURN_FI_LI (docptr, SS$_ITEMNOTFOUND) } error = wasDocPrintf (docptr, "<!--$$H:%s$$-->", renderNumericId(docptr->section)); if (error) RETURN_FI_LI (docptr, error); error = renderInsertTag (docptr, cptr); if (error) return (error); return (0); } /*****************************************************************************/ /* */ int renderInsertNote (struct wasdoc_st *docptr) { int error; char *cptr; if (dbug>1) dbugThis (FI_LI, "renderInsertNote()"); /* use the default heading */ if (!*(cptr = docptr->setNote)) cptr = DEFAULT_NOTE; /* a note is implemented as a level 6 heading */ docptr->section[6]++; error = wasDocPrintf (docptr, "<!--$$H:%s$$-->\ <h5 class=\"head center\">%s</h5>\n\ <hr class=\"note_hr\">\n", renderNumericId(docptr->section), cptr); return (error); } /*****************************************************************************/ /* The parameter URL can be absolute, relative or in-document fragment generated from a heading title. */ int renderInsertLink ( struct wasdoc_st *docptr, char *param ) { char *cptr, *sptr, *zptr; char param2 [512]; if (dbug>1) dbugThis (FI_LI, "renderInsertLink() %s", dbugAll(param)); for (cptr = param; *cptr && isalpha(*cptr); cptr++); if (MATCH3 (cptr, "://") || MATCH7 (param, "mailto:")) { /* looks like a URL scheme */ wasDocAsIs (docptr, param); } else if (strstr (cptr, "##")) { /* another document, munge the URI */ zptr = (sptr = param2) + sizeof(param2)-1; /* any trailing chunk faux "directory" must be allowed for */ if (docptr->chunked && docptr->isDynamic) if (MATCH2 (param, "./") || MATCH3 (param, "../")) for (cptr = "../"; *cptr; *sptr++ = *cptr++); /* essentially make it ODS-2 compliant */ for (cptr = param; *cptr && *cptr != '#' && sptr < zptr; cptr++) { if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' || *cptr == '.' || *cptr == '/') *sptr++ = tolower(*cptr); else *sptr++ = '_'; } if (MATCH3 (cptr, "##\0")) { for (cptr = "#0."; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; wasDocAsIs (docptr, param2); } else if (MATCH2 (cptr, "##")) { for (cptr++; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; wasDocAsIs (docptr, param2); renderFragment (docptr); } } else if (param[0] == '#') { /* explicit fragment */ wasDocEntify (docptr, param); renderFragment (docptr); } else if (param[0] == '/' || MATCH2 (param, "./") || MATCH3 (param, "../")) { /* any trailing chunk faux "directory" must be allowed for */ if (docptr->chunked && docptr->isDynamic) if (MATCH2 (param, "./") || MATCH3 (param, "../")) wasDocAsIs (docptr, "../"); /* relative URL */ wasDocEntify (docptr, param); renderFragment (docptr); } else { /* to fragment ID added via heading */ wasDocPrintf (docptr, "<!--$$L:"%s" at %s$#", param, renderSource(docptr)); wasDocEntify (docptr, param); renderFragment (docptr); wasDocAsIs (docptr, "$$-->"); } return (0); } /*****************************************************************************/ /* Create a link to another document like "Heading Name in Document Name". The parameter looks like "<URL>##<heading>++in++<document-title>". */ int renderInsertLinkIn ( struct wasdoc_st *docptr, char *param, int target ) { char *cptr, *sptr, *zptr; char heading [256], inof [256], title [256], url [256]; if (dbug>1) dbugThis (FI_LI, "renderInsertLinkIn() %d %s", target, dbugAll(param)); zptr = (sptr = url) + sizeof(url)-1; /* any trailing chunk faux "directory" must be allowed for */ if (docptr->chunked && docptr->isDynamic) if (MATCH2 (param, "./") || MATCH3 (param, "../")) for (cptr = "../"; *cptr; *sptr++ = *cptr++); /* essentially make it ODS-2 compliant */ for (cptr = param; *cptr && !MATCH2(cptr,"##") && sptr < zptr; cptr++) { if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' || *cptr == '.' || *cptr == '/') *sptr++ = tolower(*cptr); else *sptr++ = '_'; } *sptr = '\0'; if (*cptr != '#' || sptr >= zptr || !url[0]) RETURN_FI_LI (docptr, SS$_BADPARAM) zptr = (sptr = heading) + sizeof(heading)-1; for (cptr+=2; *cptr && !MATCH2(cptr,"++") && sptr < zptr; *sptr++ = *cptr++) if (*cptr == '\\' && *(cptr+1)) cptr++; *sptr = '\0'; if (*cptr != '+' || !heading[0] || sptr >= zptr) RETURN_FI_LI (docptr, SS$_BADPARAM) zptr = (sptr = inof) + sizeof(inof)-1; for (cptr+=2; *cptr && !MATCH2(cptr,"++") && sptr < zptr; *sptr++ = *cptr++) if (*cptr == '\\' && *(cptr+1)) cptr++; *sptr = '\0'; if (*cptr != '+' || !inof[0] || sptr >= zptr) RETURN_FI_LI (docptr, SS$_BADPARAM) zptr = (sptr = title) + sizeof(title)-1; for (cptr+=2; *cptr && sptr < zptr; *sptr++ = *cptr++) if (*cptr == '\\' && *(cptr+1)) cptr++; *sptr = '\0'; if (sptr >= zptr || !title[0]) RETURN_FI_LI (docptr, SS$_BADPARAM) /* the <a...href=\" has already been inserted by RenderLink() */ wasDocAsIs (docptr, url); wasDocAsIs (docptr, "#"); wasDocAsIs (docptr, heading); renderFragment (docptr); wasDocAsIs (docptr, "\">"); wasDocAsIs (docptr, heading); wasDocAsIs (docptr, "</a> "); wasDocAsIs (docptr, inof); if (target) wasDocAsIs (docptr, " <a class=\"link blank\" target=\"_blank\" href=\""); else wasDocAsIs (docptr, " <a class=\"link\" href=\""); wasDocAsIs (docptr, url); wasDocAsIs (docptr, "#0.\">"); wasDocAsIs (docptr, title); wasDocAsIs (docptr, "</a>"); return (0); } /*****************************************************************************/ /* The parameter URL can be absolute or relative. */ int renderInsertUrl ( struct wasdoc_st *docptr, char *param ) { char ch; char *cptr, *sptr, *zptr; char uri [256]; if (dbug>1) dbugThis (FI_LI, "renderInsertUrl() %s", dbugAll(param)); /* look for what might be a URL */ for (cptr = param; *cptr && (isalpha(*cptr) || !MATCH3(cptr,"://")); cptr++); if (MATCH3(cptr,"://") || MATCH7 (param, "mailto:")) { /* looks like a URL scheme */ wasDocAsIs (docptr, param); } else if (isalnum(*param) || MATCH2 (param, "./") || MATCH3 (param, "../")) { /* relative to the document location (which may be a script) */ if (docptr->isDynamic) { zptr = (sptr = uri) + sizeof(uri)-1; for (cptr = docptr->pinfo; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; while (sptr > uri && *sptr != '/') sptr--; if (MATCH2 (cptr = param, "./")) cptr += 2; while (sptr > uri) { if (!MATCH3 (cptr, "../")) break; if (sptr > uri) sptr--; while (sptr > uri && *sptr != '/') sptr--; cptr += 3; } if (sptr == uri) RETURN_FI_LI (docptr, SS$_BADPARAM) if (sptr < zptr) *sptr++ = '/'; while (*cptr && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; if (sptr >= zptr) RETURN_FI_LI (docptr, SS$_RESULTOVF) wasDocAsIs (docptr, uri); } else wasDocAsIs (docptr, param); } else wasDocAsIs (docptr, param); return (0); } /*****************************************************************************/ /* Insert the specified item into the HTML, escaped as required. */ int renderInsertOther ( struct wasdoc_st *docptr, char *param ) { static char RepeatFao [] = "!#*?\0"; static $DESCRIPTOR (DateFaoDsc, "!%D\0"); static $DESCRIPTOR (DateWidthFaoDsc, "!#%D\0"); static $DESCRIPTOR (TimeFaoDsc, "!%T\0"); static $DESCRIPTOR (TimeWidthFaoDsc, "!#%T\0"); static $DESCRIPTOR (RepeatFaoDsc, RepeatFao); int error, noescape, ignore = 0, number = 0, status, trim = 0; char *cptr, *sptr; char buf [256]; time_t t; struct tm *tmp; $DESCRIPTOR (bdsc, buf); if (dbug>1) dbugThis (FI_LI, "renderInsertOther() %s", dbugAll(param)); if (!param[0]) RETURN_FI_LI (docptr, SS$_BADPARAM) *(cptr = buf) = '\0'; if (MATCH4 (param, "cgi=")) { noescape = docptr->noescape; cptr = param + 4; while (*cptr == '!' || *cptr == '\"') { if (*cptr == '!') ignore = *cptr++; if (*cptr == '\"') noescape = *cptr++; } cptr = CgiLibVarNull (cptr); if (!cptr) if (ignore) { wasDocInsertStatus (docptr, SS$_BADPARAM); return (0); } else RETURN_FI_LI (docptr, SS$_BADPARAM) } else if (MATCH4 (param, "env=")) { noescape = docptr->noescape; cptr = param + 4; while (*cptr == '!' || *cptr == '\"') { if (*cptr == '!') ignore = *cptr++; if (*cptr == '\"') noescape = *cptr++; } cptr = getenv (cptr); if (!cptr) if (ignore) { wasDocInsertStatus (docptr, SS$_BADPARAM); return (0); } else RETURN_FI_LI (docptr, SS$_BADPARAM) } else if (MATCH4 (param, "fao=")) { param += 4; cptr = buf; noescape = docptr->noescape; if (isdigit(*param)) { number = atoi(param); if (number > sizeof(buf)-1) number = sizeof(buf)-1; while (isdigit(*param)) param++; } if (MATCH2 (param, "%D")) if (number) sys$fao (&DateWidthFaoDsc, 0, &bdsc, number, 0); else sys$fao (&DateFaoDsc, 0, &bdsc, 0); else if (MATCH2 (param, "%T")) if (number) sys$fao (&TimeWidthFaoDsc, 0, &bdsc, number, 0); else sys$fao (&TimeFaoDsc, 0, &bdsc, 0); else if (param[0] == '*' && param[1]) { RepeatFao[3] = param[1]; sys$fao (&RepeatFaoDsc, 0, &bdsc, number, 0); } else cptr = NULL; } else if (MATCH5 (param, "file=")) return (renderInsertFile (docptr, param+5, 0)); else if (MATCH12 (param, "locale=ctype")) cptr = setlocale (LC_CTYPE, NULL); else if (MATCH7 (param, "locale=")) cptr = setlocale (atoi(param+8), NULL); else if (MATCH7 (param, "locale")) cptr = setlocale (LC_ALL, NULL); else if (MATCH8 (param, "include=")) return (renderIncludeFile (docptr, param+8)); else if (MATCH8 (param, "Include=")) return (0); else if (MATCH6 (param, "spawn=")) return (SpawnCommand (docptr, param+6, NULL)); else if (MATCH4 (param, "syi=")) cptr = renderGetSyi (docptr, param+4); else if (MATCH4 (param, "time")) { if (param[4] == '=') cptr = param + 5; else cptr = "%a, %d %b %Y %T %z"; t = time(NULL); tmp = localtime(&t); if (!tmp) RETURN_FI_LI (docptr, SS$_BADPARAM) if (!strftime (buf, sizeof(buf), cptr, tmp)) RETURN_FI_LI (docptr, SS$_BADPARAM) cptr = buf; } else if (MATCH4 (param, "lnm=")) { int report = 0; noescape = docptr->noescape; for (cptr = sptr = param + 4; *cptr == '!' || *cptr == '\"'; cptr++) { if (*cptr == '!') report = 1; if (*cptr == '\"') noescape = 1; } cptr = renderTrnLnm (docptr, cptr, report); } else if (MATCH7 (param, "wasdoc=")) { if (MATCH8 (param+7, "version")) cptr = SoftwareVersion; else if (MATCH8 (param+7, "software")) cptr = SoftwareID; else if (MATCH5 (param+7, "path")) cptr = docptr->pinfo; else if (MATCH10 (param+7, "directory")) cptr = docptr->dname; } else if (isupper(param[0])) { /* insert the flag value */ noescape = 1; cptr = renderFlag (docptr, param, 0); } if (!cptr || !*cptr) RETURN_FI_LI (docptr, SS$_BADPARAM) if (noescape) wasDocAsIs (docptr, cptr); else wasDocEntify (docptr, cptr); return (0); } /*****************************************************************************/ /* Insert the content of the specified file into the HTML, escaped as required. */ int renderInsertFile ( struct wasdoc_st *docptr, char *fname, int noescape ) { int bytes, error, ignore = 0; char *cptr, *fnptr, *sptr, *zptr; FILE *ifptr; stat_t fstatbuf; if (dbug>1) dbugThis (FI_LI, "renderInsertFile() %d %s", noescape, dbugAll(fname)); if (!noescape) noescape = docptr->noescape ? 1 : 0; fnptr = fname; while (*fnptr == '!' || *fnptr == '\"') { if (*fnptr == '!') ignore = *fnptr++; if (*fnptr == '\"') noescape = *fnptr++; } if (!*fnptr) { /* empty specification means include self */ if (noescape) wasDocAsIs (docptr, docptr->text); else wasDocEntify (docptr, docptr->text); return (0); } cptr = getenv("PATH"); chdir (docptr->dname); ifptr = fopen (fnptr, "r"); error = vaxc$errno; chdir (cptr); if (!ifptr) { if (!ignore) return (error); wasDocInsertStatus (docptr, error); return (0); } if (fstat (fileno(ifptr), &fstatbuf) < 0) { error = vaxc$errno; fclose (ifptr); if (!ignore) return (error); wasDocInsertStatus (docptr, error); return (0); } /* extra bytes allow EOF when reading past the EOF */ bytes = fstatbuf.st_size; bytes += 32; cptr = sptr = calloc (1, bytes); if (!cptr) exit (vaxc$errno); /* read the entire file into memory */ while (fgets (sptr, bytes-(sptr-cptr), ifptr)) while (*sptr) sptr++; fclose (ifptr); if (noescape) wasDocAsIs (docptr, cptr); else wasDocEntify (docptr, cptr); free (cptr); return (0); } /*****************************************************************************/ /* Insert the content of the specified file into the source TEXT at the current parse position. The parser will then just continue with the included text. If it has a ".css" type then we'll assume style has been set. */ int renderIncludeFile ( struct wasdoc_st *docptr, char *fname ) { static char asis1 [] = "\n|asis|\n", asis2 [] = "||||\n"; int asis = 0, bytes, error, ignore = 0; char *aptr, *cptr, *fnptr, *sptr, *tptr, *zptr; FILE *ifptr; stat_t fstatbuf; if (dbug>1) dbugThis (FI_LI, "renderIncludeFile() %s", dbugAll(fname)); fnptr = fname; while (*fnptr == '!' || *fnptr == '\"') { if (*fnptr == '!') ignore = *fnptr++; if (*fnptr == '\"') asis = *fnptr++; } /* if file extension is ".css" then assume the document has been styled */ for (cptr = fnptr; *cptr; cptr++); while (cptr > fnptr && *cptr != '.' && !MATCH2((cptr-1), "^.")) cptr--; if (!strcasecmp (cptr, ".css")) docptr->styled = 1; if (dbug>1) dbugThis (FI_LI, "%s\n", dbugAll(fnptr)); cptr = getenv("PATH"); chdir (docptr->dname); ifptr = fopen (fnptr, "r"); error = vaxc$errno; chdir (cptr); if (!ifptr) { if (!ignore) return (error); wasDocInsertStatus (docptr, error); return (0); } if (fstat (fileno(ifptr), &fstatbuf) < 0) { error = vaxc$errno; fclose (ifptr); if (ignore) return (0); return (error); } /* extra bytes allow EOF when reading past the EOF */ bytes = fstatbuf.st_size + 32; aptr = sptr = calloc (1, bytes); if (!cptr) exit (vaxc$errno); /* read the entire file into memory */ while (fgets (sptr, bytes-(sptr-aptr), ifptr)) while (*sptr) sptr++; fclose (ifptr); /* adjust bytes to reflect the actual content */ bytes = sptr - aptr; docptr->tsize += bytes; if (asis) { asis = sizeof(asis1)-1 + sizeof(asis2)-1; docptr->tsize += asis; } docptr->text = realloc (docptr->text, docptr->tsize); if (!docptr->text) exit (vaxc$errno); /* current parse position should be just before the end of the tag */ tptr = docptr->text + docptr->tparse; if (MATCH2 (tptr, "||")) tptr++; if (*tptr == '|') tptr++; if (isspace(*tptr)) tptr++; /* first move the current content up */ memmove (tptr + bytes + asis, sptr = tptr, docptr->tlength - (tptr - docptr->text)); /* then insert the text into the space created */ if (asis) for (cptr = asis1; *cptr; *sptr++ = *cptr++); memmove (sptr, aptr, bytes); sptr += bytes; if (asis) for (cptr = asis2; *cptr; *sptr++ = *cptr++); free (aptr); if (isspace(*(tptr-1))) tptr--; docptr->tparse = tptr - docptr->text; docptr->tlength += bytes + asis; return (0); } /*****************************************************************************/ /* The trailing document text needs to be reduced to an alphanumeric ID (fragment). It is bounded by a leading hash. Squash it down to that ID and adjust the document length. */ void renderFragment (struct wasdoc_st *docptr) { char *aptr, *cptr, *sptr; for (sptr = docptr->html + docptr->hlength; sptr > docptr->html && *sptr != '#' && *sptr != '\"' && *sptr != '>'; sptr--); if (dbug>1) dbugThis (FI_LI, "renderFragment() %s", dbugAll(aptr = sptr)); if (*sptr != '#') return; for (cptr = ++sptr; *cptr; cptr++) if (isalnum (*cptr)) *sptr++ = tolower(*cptr); *sptr = '\0'; if (dbug>1) dbugThis (FI_LI, "%s", dbugAll(aptr)); docptr->hlength = sptr - docptr->html; } /*****************************************************************************/ /* Insert a tag and any tag attributes into the HTML. An attribute (&-introduced and |-delimited) string can be used. Characters may be escaped. It a style string. Return zero for success or an error code. */ int renderInsertTag ( struct wasdoc_st *docptr, char *tag ) { int div = 0, clidx, head = 0, idx, image = 0, link = 0, linkimg = 0, list = 0, noescape = 0, note = 0, span = 0, table = 0, tabr = 0, tabh = 0, tabd = 0, tenths = 0; char *cptr, *sptr, *tptr, *zptr; char *align = "", *backlight = "", *blank = "", *bold = "", *inblock = "", *indent = "", *italic = "", *wrap = "", *mono = "", *strike = "", *tabauto = "", *target = "", *under = "", *valign = "", *zero = ""; char *class [8]; char colspan [32] = "", empad [32] = "", fname[64], rowspan [32] = ""; for (clidx = 0; (clidx * sizeof(char*)) < sizeof(class); clidx++) class[clidx] = NULL; clidx = 0; if (HMORE (docptr)) wasDocMoreHtml (docptr); tptr = docptr->text + docptr->tparse; sptr = docptr->html + docptr->hlength; /* right to the end of the buffer */ zptr = docptr->html + docptr->hsize; if (dbug>1) dbugThis (FI_LI, "renderInsertTag() %c%s%c %s", bvbar, tag, bvbar, dbugMax(tptr)); if (!(span = MATCH5 (tag, "<span"))) if (!(div = MATCH4 (tag, "<div"))) if (!(head = MATCH2 (tag, "<h"))) if (!(link = MATCH3 (tag, "<a "))) if (!(link = linkimg = MATCH3 (tag, "<aimg "))) /* faux tag */ if (!(image = MATCH4 (tag, "<img"))) if (!(list = MATCH3 (tag, "<li"))) if (!(list = MATCH3 (tag, "<ol"))) if (!(list = MATCH3 (tag, "<sl"))) /* faux tag */ if (!(list = MATCH3 (tag, "<ul"))) if (!(table = MATCH4 (tag, "<tab"))) if (!(tabr = MATCH3 (tag, "<tr"))) if (!(tabh = MATCH3 (tag, "<th"))) if (!(tabd = MATCH3 (tag, "<td"))) wasDocBugcheck(FI_LI); if (div) docptr->bflag[++docptr->bfindex] = 0; if (span) { cptr = "<span class=\"high" ; while (*cptr && sptr < zptr) *sptr++ = *cptr++; for (tptr++; isalpha(*tptr) && sptr < zptr; *sptr++ = *tptr++); cptr = NULL; } else if (div) { if (MATCH5 (tptr, "|note")) cptr = "<div class=\""; else if (MATCH5 (tptr, "|draw")) { cptr = "<div class=\"drawing dfont "; indent = " indent"; } else cptr = "<div class=\"blockof "; while (*cptr && sptr < zptr) *sptr++ = *cptr++; for (tptr++; isalpha(*tptr) && sptr < zptr; *sptr++ = *tptr++); cptr = NULL; } else if (list) { if (MATCH3 (tag, "<li")) cptr = "<li class=\"item"; else if (MATCH3 (tag, "<ol")) cptr = "<ol class=\"list"; else if (MATCH3 (tag, "<ul")) cptr = "<ul class=\"list"; else cptr = "<ul class=\"list simple"; } else if (table) { if (MATCH6 (tptr, "|table")) cptr = "<table class=\"tabl"; else cptr = "<table class=\"tabu"; if (docptr->bflag[docptr->bfindex] & BFLAG_CENTER) tabauto = " tabauto"; } else if (tabr) { if (MATCH2 (tptr, "|~")) tptr++; cptr = "<tr class=\"tabr"; } else if (tabh) { if (MATCH2 (tptr, "|:")) tptr++; cptr = "<th class=\"tabh"; } else if (tabd) { if (MATCH2 (tptr, "|.")) tptr++; cptr = "<td class=\"tabd"; } else if (link) cptr = "<a class=\"link"; else if (image) cptr = "<img class=\"image"; else if (head) { if (MATCH3 (tag, "<h9")) { for (cptr = "<h6"; *cptr && sptr < zptr; *sptr++ = *cptr++); cptr = " class=\"head display0"; } else { for (cptr = tag; *cptr && sptr < zptr; *sptr++ = *cptr++); if (docptr->notable == NOTE_HEADING) cptr = " class=\"head center"; else cptr = " class=\"head"; } } if (cptr) { while (*cptr && sptr < zptr) *sptr++ = *cptr++; /* span over the tag characters */ if (head) for (tptr++; isdigit(*tptr); tptr++); else for (tptr++; isalpha(*tptr); tptr++); } for (; *tptr; tptr++) { /* special case, cross-reference elipsis */ if (head && MATCH3 (tptr, "...")) break; if (MATCH2 (tptr, "\\\n")) { tptr++; continue; } if ((tabd || tabh) && *tptr >= '1' && *tptr <= '9') { /* table heads and data are allowed digits */ if (tabh || tabd) { if (!colspan[0]) sprintf (colspan, " colspan=\"%c\"", *tptr); else sprintf (rowspan, " rowspan=\"%c\"", *tptr); } continue; } if (*tptr == '&') break; /* rest of string is style */ /* vbar or period or not-punctuation ends markup */ if (*tptr == '|' || *tptr == '.' || *tptr == '\\' || !ispunct(*tptr)) break; /* and if a table element then a space too */ if ((tabr || tabd || tabh) && isspace(*tptr)) break; if (*tptr == '*') bold = " bold"; else if (*tptr == '/') italic = " italic"; else if (*tptr == '_') under = " under"; else if (*tptr == '=') mono = " monosp"; else if (*tptr == '-' && span) strike = " strike"; else if (*tptr == '-' && !span) indent = " noindent"; else if (*tptr == '+' && !span) indent = " indent"; else if (MATCH2 (tptr, "<<")) { wrap = " prewrap"; tptr++; } else if (MATCH2 (tptr, ">>")) { wrap = " nowrap"; tptr++; } else if (MATCH2 (tptr, "><")) { if (table) tabauto = " tabauto"; else align = " center"; if (div) docptr->bflag[docptr->bfindex] |= BFLAG_CENTER; tptr++; } else if (*tptr == '>') { align = " right"; if (div) docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER; } else if (*tptr == '<') { align = " left"; if (div) docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER; } else if (MATCH2 (tptr, "#+")) { /* vertical align top */ valign = " valtop"; tptr++; } else if (MATCH2 (tptr, "#=")) { /* vertical align middle */ valign = " valmid"; tptr++; } else if (MATCH2 (tptr, "#-")) { /* vertical align bottom */ valign = " valbot"; tptr++; } else if (MATCH2 (tptr, "#*")) { /* enable row highlight only for any outermost table */ if (tabr && docptr->table == 1 && !docptr->rowlight) docptr->rowlight++; else /* otherwise apply a backlight to the element */ if (!tabr) backlight = " backlight"; tptr++; } else if (MATCH3 (tptr, "#^*")) { /* make this row the same highlight as the previous row */ if (tabr && docptr->table == 1) if (docptr->rowlight & 1) docptr->rowlight--; else if (docptr->rowlight) docptr->rowlight++; tptr += 2; } else if (MATCH3 (tptr, "#!*")) { /* disable row highlight only for any outermost table */ if (tabr && docptr->table == 1) docptr->rowlight = 0; tptr += 2; } else if (MATCH3 (tptr, "#1*")) { /* one-shot to any element but escpecially for table row */ backlight = " backlight"; tptr += 2; } else if (MATCH2 (tptr, "##")) { /* padding in 0.1 ems */ tptr++; tenths = atoi(tptr+1); while (isdigit (*(tptr+1))) tptr++; if (tenths) sprintf (empad, "padding:%1.1fem;", (float)tenths / 10.0); } else if (MATCH3 (tptr, "#::")) { /* inline-block */ inblock = " inblock"; tptr + 2; } else if (*tptr == '#') { if (list) zero = " list0"; else if (tabr || tabh || tabd) zero = " tab0"; else zero = " display0"; } else if (*tptr == '%') { if (link) { if (!linkimg) blank = " blank"; target = " target=\"_blank\""; } else if (image) { /* % used to create a link to the image, see |image| */ tptr++; if (*tptr == '%') tptr++; } } else if (*tptr == '\'') { /* single quote - append this class */ if (tptr[1] == '_' || isalpha(tptr[1])) { class[clidx] = tptr + 1; if ((clidx * sizeof(char*)) < sizeof(class)) clidx++; if (tptr[1] == '_') tptr++; while (isalnum(tptr[1])) tptr++; } } else if (*tptr == '\"') /* 1 is "standalone" and 2 is a <span>/<div> */ noescape = docptr->noescape = 2; } /* apply row highlight only for any outermost table */ if (tabr && docptr->rowlight && docptr->table == 1) if (docptr->rowlight++ & 1) backlight = " backlight"; for (cptr = align; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = backlight; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = blank; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = bold; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = inblock; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = indent; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = italic; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = mono; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = strike; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = tabauto; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = under; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = valign; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = wrap; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = zero; *cptr && sptr < zptr; *sptr++ = *cptr++); /* append additional explicitly specified class names */ for (clidx = 0; (clidx * sizeof(char*)) < sizeof(class); clidx++) if (class[clidx]) { if (sptr < zptr) *sptr++ = ' '; for (cptr = class[clidx]; *cptr && (*cptr == '_' || isalnum(*cptr)) && sptr < zptr; *sptr++ = *cptr++); } /* end of classes */ if (sptr < zptr) *sptr++ = '\"'; /* links can have additional attributes */ for (cptr = target; *cptr && sptr < zptr; *sptr++ = *cptr++); /* table rows and columns can have additional attributes */ for (cptr = colspan; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = rowspan; *cptr && sptr < zptr; *sptr++ = *cptr++); if (*tptr == '&' || empad[0]) { /* append style string */ for (cptr = " style=\""; *cptr && sptr < zptr; *sptr++ = *cptr++); if (*tptr == '&') { for (tptr++; *tptr && sptr < zptr;) { if (MATCH2 (tptr, "\\\n")) { tptr++; continue; } if (*tptr == '|') break; if (MATCH2 (tptr, ";.") || MATCH2 (tptr, ";\\")) { *sptr++ = *tptr++; if (MATCH2 (tptr, "\\\n")) continue; break; } if (*tptr == '\\' && tptr[1]) tptr++; *sptr++ = *tptr++; } } for (cptr = empad; *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr < zptr) *sptr++ = '\"'; } if (image) for (cptr = " src=\""; *cptr && sptr < zptr; *sptr++ = *cptr++); else if (link) for (cptr = " href=\""; *cptr && sptr < zptr; *sptr++ = *cptr++); else if (sptr < zptr) *sptr++ = '>'; *sptr = '\0'; if (!(head && MATCH3 (tptr, "..."))) { if (*tptr == '.') tptr++; else /* a " flag must be terminated by a period */ if (noescape && *tptr != '\\' && *tptr != '|') RETURN_FI_LI (docptr, SS$_BADPARAM) } if (dbug>1) dbugThis (FI_LI, "%s", dbugMax(tptr)); docptr->tparse = tptr - docptr->text; docptr->hlength = sptr - docptr->html; if (HMORE (docptr)) wasDocMoreHtml (docptr); if (sptr >= zptr) return (SS$_BADPARAM); else return (0); } /*****************************************************************************/ /* Set document style element. If parameter is NULL then default style. */ int renderStyle ( struct wasdoc_st *docptr, char *param ) { int error = 0; char *cptr, *sptr, *zptr; if (dbug>1) dbugThis (FI_LI, "renderStyle() %s", dbugAll(param)); if (!param || MATCH7 (param, "default")) { if (!docptr->styled) wasDocAsIs (docptr, styleDefault); docptr->styled = 1; } else if (MATCH6 (param, "chunk=")) { if (docptr->chunked) wasDocPrintf (docptr, "<style type=\"text/css\">%s</style>", param+6); } else if (MATCH5 (param, "file=")) { renderInsertFile (docptr, param+5, 1); docptr->styled = 1; } else if (MATCH6 (param, "sheet=")) { wasDocPrintf (docptr, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">\n", param + 6); docptr->styled = 1; } else { for (cptr = param; *cptr && *cptr != '=' && *cptr != '{'; cptr++); if (*cptr == '=') error = SS$_BADPARAM; else wasDocPrintf (docptr, "<style type=\"text/css\">%s</style>", param); } return (error); } /*****************************************************************************/ /* Translate a logical name. The parameter name can followed by a semi-colon and a table name, otherwise LNM$FILE_DEV is used. Returns a pointer to the value or NULL if an error (including not existing). Document insight can show the status returned. */ char* renderTrnLnm ( struct wasdoc_st *docptr, char *param, int report ) { static unsigned short slen; static char value [256]; static $DESCRIPTOR (nameDsc, ""); static $DESCRIPTOR (tableDsc, ""); static struct { short int buf_len; short int item; void *buf_addr; unsigned short *ret_len; } items [] = { { 255, LNM$_STRING, value, &slen }, { 0,0,0,0 } }; int status; char *cptr; if (dbug>1) fprintf (stdout, "renderTrnLnm() %s\n", param); /* <log-name>[;<log-table>]*/ for (cptr = param; *cptr && *cptr != ';'; cptr++); nameDsc.dsc$a_pointer = param; nameDsc.dsc$w_length = cptr - nameDsc.dsc$a_pointer; if (*cptr == ';') { tableDsc.dsc$a_pointer = ++cptr; while (*cptr) cptr++; tableDsc.dsc$w_length = cptr - tableDsc.dsc$a_pointer; } else { tableDsc.dsc$a_pointer = "LNM$FILE_DEV"; tableDsc.dsc$w_length = 12; } status = sys$trnlnm (0, &tableDsc, &nameDsc, 0, &items); if (dbug>1) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status); if (!(status & 1)) { if (!report) { if (docptr->insight >= 5) wasDocInsight (docptr, "%%X%08.08X", status); return (NULL); } sprintf (value, "%%X%08.08X", status); } else value[slen] = '\0'; if (docptr->insight >= 5) wasDocInsight (docptr, "%s", value); return (value); } /*****************************************************************************/ /* Copy a string where a '|' terminates and the '\' escapes the next character. */ int renderGetEscaped ( char *string, char *buf, int size ) { char *cptr, *sptr, *zptr; zptr = (sptr = buf) + size - 1; if (sptr > zptr) return (SS$_RESULTOVF); for (cptr = string; *cptr && sptr < zptr; cptr++) { if (*cptr == '|') break; if (*cptr == '\\' && cptr[1]) cptr++; *sptr++ = *cptr; } *sptr = '\0'; if (sptr > zptr) return (SS$_RESULTOVF); return (0); } /*****************************************************************************/ /* Remove preceding white-space. */ char* renderTrimWhite (struct wasdoc_st *docptr) { char *cptr; while (docptr->hlength && isspace(docptr->html[docptr->hlength-1])) docptr->hlength--; docptr->html[docptr->hlength] = '\0'; cptr = docptr->html + docptr->hlength; if (docptr->hlength) cptr--; return (cptr); } /*****************************************************************************/ /* Return a pointer the string representation of the specified $GETSYI item. Return NULL on error. Definitely not reentrant. */ char* renderGetSyi ( struct wasdoc_st *docptr, char *param ) { static int PrevCgiPlusCount; static ulong SyiClusterEVotes, SyiClusterMember, SyiClusterNodes, SyiClusterQuorum, SyiClusterVotes, SyiMemSize, SyiPageSize; static ulong SyiBootTime [2], time64 [2], upTime64 [2]; static char bootTime [24], clevotes [16], clmember [16], clnodes [16], clquorum [16], clvotes [16], memSize [16], SyiArchName [16], SyiHwName [64], SyiNodeName [16], SyiVersion [12], upTime [24]; static struct { short buf_len; short item; char *buf_addr; short *short_ret_len; } SyiItem [] = { { sizeof(SyiArchName), SYI$_ARCH_NAME, (char*)&SyiArchName, 0 }, { sizeof(SyiBootTime), SYI$_BOOTTIME, (char*)&SyiBootTime, 0 }, { sizeof(SyiClusterEVotes), SYI$_CLUSTER_EVOTES, (char*)&SyiClusterEVotes, 0 }, { sizeof(SyiClusterMember), SYI$_CLUSTER_MEMBER, (char*)&SyiClusterMember, 0 }, { sizeof(SyiClusterNodes), SYI$_CLUSTER_NODES, (char*)&SyiClusterNodes, 0 }, { sizeof(SyiClusterQuorum), SYI$_CLUSTER_QUORUM, (char*)&SyiClusterQuorum, 0 }, { sizeof(SyiClusterVotes), SYI$_CLUSTER_VOTES, (char*)&SyiClusterVotes, 0 }, { sizeof(SyiHwName), SYI$_HW_NAME, (char*)&SyiHwName, 0 }, { sizeof(SyiMemSize), SYI$_MEMSIZE, (char*)&SyiMemSize, 0 }, { sizeof(SyiNodeName), SYI$_NODENAME, (char*)&SyiNodeName, 0 }, { sizeof(SyiPageSize), SYI$_PAGE_SIZE, (char*)&SyiPageSize, 0 }, { sizeof(SyiVersion), SYI$_VERSION, (char*)&SyiVersion, 0 }, { 0,0,0,0 } }; $DESCRIPTOR (bootFaoDsc, "!20%D\0"); $DESCRIPTOR (bootTimeDsc, bootTime); $DESCRIPTOR (upFaoDsc, "!%D"); $DESCRIPTOR (upTimeDsc, upTime); int status; short slen; double fmem; char *cptr = NULL; if (dbug>1) dbugThis (FI_LI, "renderGetSyi() %s", dbugAll(param)); if (!param[0]) return (NULL); if (CgiPlusCount > PrevCgiPlusCount) { PrevCgiPlusCount = CgiPlusCount; SyiArchName[0] = '\0'; } if (!SyiArchName[0]) if ((status = sys$getsyi (0, 0, 0, &SyiItem, 0, 0, 0)) & 1) { fmem = (double)SyiMemSize * (double)SyiPageSize; if (fmem >= 1073741824.0) sprintf (memSize, "%.02fGB", fmem / 1073741824.0); else if (fmem >= 1048576.0) sprintf (memSize, "%.02fMB", fmem / 1048576.0); else sprintf (memSize, "%.02fkB", fmem / 1024.0); sys$fao (&bootFaoDsc, 0, &bootTimeDsc, &SyiBootTime); sys$gettim (&time64); lib$sub_times (&time64, &SyiBootTime, &upTime64); sys$fao (&upFaoDsc, &slen, &upTimeDsc, &upTime64); upTime[slen-3] = '\0'; } else { sprintf (SyiArchName, "%%X%08.08X", status); strcpy (bootTime, SyiArchName); strcpy (memSize, SyiArchName); strcpy (SyiHwName, SyiArchName); strcpy (SyiNodeName, SyiArchName); strcpy (SyiVersion, SyiArchName); strcpy (upTime, SyiArchName); SyiMemSize = 0; } if (MATCH7 (param, "arch_name")) cptr = SyiArchName; else if (MATCH8 (param, "cluster=")) { if (MATCH6 (param+8, "evotes")) sprintf (cptr = clevotes, "%d", SyiClusterEVotes); else if (MATCH6 (param+8, "member")) sprintf (cptr = clmember, "%d", SyiClusterMember); else if (MATCH5 (param+8, "nodes")) sprintf (cptr = clnodes, "%d", SyiClusterNodes); else if (MATCH6 (param+8, "quorum")) sprintf (cptr = clquorum, "%d", SyiClusterQuorum); else if (MATCH5 (param+8, "votes")) sprintf (cptr = clvotes, "%d", SyiClusterVotes); } else if (MATCH8 (param, "boottime")) cptr = bootTime; else if (MATCH7 (param, "hw_name")) cptr = SyiHwName; else if (MATCH7 (param, "memsize")) cptr = memSize; else if (MATCH8 (param, "nodename")) cptr = SyiNodeName; else if (MATCH6 (param, "uptime")) cptr = upTime; else if (MATCH7 (param, "version")) cptr = SyiVersion; if (!cptr || !*cptr) return (NULL); return (cptr); } /*****************************************************************************/ /* "n." or "n.n" or "n.n.n" or ... */ char* renderNumericId (int *digit6) { static char buf [48]; int cnt, idx; char *sptr; sptr = buf; for (cnt = 6; cnt > 1 && !digit6[cnt]; cnt--); for (idx = 1; idx <= cnt; idx++) sptr += sprintf (sptr, "%d.", digit6[idx]); if (cnt > 1) *(sptr-1) = '\0'; if (dbug>1) dbugThis (FI_LI, "renderNumericId() %s", buf); return (buf); } /*****************************************************************************/ /* Delineate a tag. See module prologue for a description of tag syntax. */ void renderInsightTag (struct wasdoc_st *docptr) { char *aptr, *cptr, *sptr, *tptr, *zptr; char buf [256]; tptr = docptr->text + docptr->tparse; if (dbug>1) dbugThis (FI_LI, "renderInsightTag() %s", dbugMax(tptr)); if (MATCH6 (tptr, "\n||||\n")) { wasDocInsight (docptr, "||||"); return; } if (MATCH2 (tptr, "||") || MATCH2 (tptr, "| ") || MATCH2 (tptr, "|\n") || MATCH2 (tptr, "|\t")) { wasDocInsight (docptr, "||"); return; } if (MATCH2 (tptr, "|!")) { for (cptr = tptr + 2; *cptr && *cptr != '|'; cptr++); wasDocInsight (docptr, "%*.*s", cptr-tptr+1, cptr-tptr+1, tptr); return; } if (MATCH5 (tptr, "|...|") || MATCH5 (tptr, "|:::|")) { wasDocInsight (docptr, "%5.5s", tptr); return; } if (MATCH4 (tptr, "|--|")) { wasDocInsight (docptr, "%4.4s", tptr); return; } if (MATCH3 (tptr, "|-|") || MATCH3 (tptr, "|^+") || MATCH3 (tptr, "|^-")) { wasDocInsight (docptr, "%3.3s", tptr); return; } if (MATCH3 (tptr, "|^ ") || MATCH3 (tptr, "|^\t") || MATCH3 (tptr, "|^\n")) { wasDocInsight (docptr, "%2.2s", tptr); return; } if (MATCH2 (tptr, "|0") || MATCH2 (tptr, "|1") || MATCH2 (tptr, "|2") || MATCH2 (tptr, "|3") || MATCH2 (tptr, "|4") || MATCH2 (tptr, "|9")) { if (docptr->insight >= 5) { for (cptr = tptr + 1; *cptr && *cptr != '|'; cptr++); wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr); } else if (docptr->insight >= 4) { for (cptr = tptr + 1; *cptr && !isalpha(*cptr); cptr++); wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr); } else wasDocInsight (docptr, "%2.2s", tptr); return; } if (MATCH2 (tptr, "|~") || MATCH2 (tptr, "|:") || MATCH2 (tptr, "|.") || MATCH2 (tptr, "|&")) { if (docptr->insight >= 5) for (cptr = tptr; *cptr && !isspace(*cptr); cptr++); else cptr = tptr + 2; wasDocInsight (docptr, "%*.*s", cptr-tptr, cptr-tptr, tptr); return; } if (*tptr == '|' && ispunct(tptr[1])) { zptr = (sptr = buf) + sizeof(buf)-1; *sptr++ = *tptr++; for (cptr = tptr; *cptr && sptr < zptr; cptr++) { if (*cptr == '&' || *cptr == '\\' || *cptr == '.' || *cptr == '|') { if (*cptr == '&') *sptr++ = *cptr; break; } if (*cptr == '\'') { *sptr++ = *cptr; for (cptr++; isalpha(*cptr); cptr++); continue; } if (isalpha(*cptr)) break; *sptr++ = *cptr; } *sptr = '\0'; wasDocInsight (docptr, "%s", buf); return; } if ((MATCH5 (tptr, "|asis") && ispunct(tptr[5])) || (MATCH6 (tptr, "|block") && ispunct(tptr[6])) || (MATCH6 (tptr, "|break")&& ispunct(tptr[6])) || (MATCH7 (tptr, "|bullet") && ispunct(tptr[7])) || (MATCH5 (tptr, "|code") && ispunct(tptr[5])) || (MATCH5 (tptr, "|data") && ispunct(tptr[5])) || (MATCH5 (tptr, "|draw") && ispunct(tptr[5])) || (MATCH5 (tptr, "|elif") && ispunct(tptr[5])) || (MATCH5 (tptr, "|else") && ispunct(tptr[5])) || (MATCH6 (tptr, "|endif") && ispunct(tptr[6])) || (MATCH8 (tptr, "|example") && ispunct(tptr[8])) || (MATCH5 (tptr, "|exit") && ispunct(tptr[5])) || (MATCH5 (tptr, "|head") && ispunct(tptr[5])) || (MATCH5 (tptr, "|hide") && ispunct(tptr[5])) || (MATCH6 (tptr, "|image") && ispunct(tptr[6])) || (MATCH6 (tptr, "|index") && ispunct(tptr[6])) || (MATCH7 (tptr, "|insert") && ispunct(tptr[7])) || (MATCH9 (tptr, "|insight!") && ispunct(tptr[9])) || (MATCH9 (tptr, "|insight@") && ispunct(tptr[9])) || (MATCH3 (tptr, "|if") && ispunct(tptr[3])) || (MATCH7 (tptr, "|inline") && ispunct(tptr[7])) || (MATCH6 (tptr, "|insert") && ispunct(tptr[6])) || (MATCH5 (tptr, "|item") && ispunct(tptr[5])) || (MATCH3 (tptr, "|li") && ispunct(tptr[3])) || (MATCH5 (tptr, "|link") && ispunct(tptr[5])) || (MATCH7 (tptr, "|mailto") && ispunct(tptr[7])) || (MATCH5 (tptr, "|mono") && ispunct(tptr[5])) || (MATCH5 (tptr, "|note") && ispunct(tptr[5])) || (MATCH8 (tptr, "|noprint") && ispunct(tptr[8])) || (MATCH7 (tptr, "|number") && ispunct(tptr[7])) || (MATCH3 (tptr, "|ol") && ispunct(tptr[3])) || (MATCH6 (tptr, "|ppage") && ispunct(tptr[6])) || (MATCH6 (tptr, "|print") && ispunct(tptr[6])) || (MATCH5 (tptr, "|prop") && ispunct(tptr[5])) || (MATCH6 (tptr, "|quote") && ispunct(tptr[6])) || (MATCH4 (tptr, "|row") && ispunct(tptr[4])) || (MATCH3 (tptr, "|tr") && ispunct(tptr[3])) || (MATCH4 (tptr, "|set") && ispunct(tptr[4])) || (MATCH7 (tptr, "|simple") && ispunct(tptr[7])) || (MATCH3 (tptr, "|sl") && ispunct(tptr[3])) || (MATCH6 (tptr, "|style") && ispunct(tptr[6])) || (MATCH6 (tptr, "|table") && ispunct(tptr[6])) || (MATCH8 (tptr, "|tabular") && ispunct(tptr[8])) || (MATCH4 (tptr, "|toc") && ispunct(tptr[4])) || (MATCH3 (tptr, "|ul") && ispunct(tptr[3]))) { if (docptr->insight >= 5) { if (MATCH4 (tptr, "|set") || MATCH6 (tptr, "|style")) { for (cptr = tptr + 1; *cptr && *cptr != '|'; cptr++); if (*cptr) cptr++; while (*cptr && *cptr != '|') cptr++; } else for (cptr = tptr + 1; *cptr; cptr++) if (*cptr == '\\' || *cptr == '.' || *cptr == '|') break; } else for (cptr = tptr + 1; isalpha(*cptr); cptr++); wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr); return; } cptr = tptr + 1; if (*cptr == '%') cptr++; while (*cptr && cptr < tptr+8 && isalpha(*cptr)) cptr++; if (MATCH3 (cptr, "://")) { wasDocInsight (docptr, "|link|"); return; } wasDocInsight (docptr, "\?\?\?"); } /*****************************************************************************/ /* Display the source text file name. */ void renderInsightSource ( struct wasdoc_st *docptr, char *tptr ) { char *cptr; for (cptr = tptr; *cptr && *cptr != ' '; cptr++); wasDocInsight (docptr, "%*.*s", cptr-tptr, cptr-tptr, tptr); } /*****************************************************************************/ /* Document the stack contents. */ void renderInsightStack (struct wasdoc_st *docptr) { int idx; char *aptr, *cptr, *sptr, *zptr; char buf [1024]; for (idx = 1; idx < STACK_MAX && docptr->cstack[idx]; idx++); idx--; for (; idx; idx--) { if (!docptr->cstack[idx]) continue; zptr = (sptr = buf) + sizeof(buf)-1; sptr += sprintf (sptr, "☰%d%s", idx, idx == docptr->stindex ? "✓ ※" : " ※"); for (cptr = docptr->cstack[idx]; *cptr && *cptr != '\n'; cptr++) { aptr = NULL; if (*cptr == '<') aptr = "<"; if (*cptr == '>') aptr = ">"; if (*cptr == '&') aptr = "&"; if (aptr) while (*aptr && sptr < zptr) *sptr++ = *aptr++; else if (sptr < zptr) *sptr++ = *cptr; } for (cptr = " ※"; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = docptr->tstack[idx]; *cptr && *cptr != '\n'; cptr++) { aptr = NULL; if (*cptr == '<') aptr = "<"; if (*cptr == '>') aptr = ">"; if (*cptr == '&') aptr = "&"; if (aptr) while (*aptr && sptr < zptr) *sptr++ = *aptr++; else if (sptr < zptr) *sptr++ = *cptr; } *sptr = '\0'; wasDocInsight (docptr, "%s", buf); } } /*****************************************************************************/