[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]
/*****************************************************************************/
/*
                                   pass2.c

RENDER.C generates a first-pass HTML document.

PASS2.C generates the final HTML document, in particular populating headings
and links, and generating cross-referencing, tables of content, and an index.


VERSION HISTORY
---------------
29-APR-2020  MGD  initial
*/
/*****************************************************************************/

#include "wasdoc.h"
#include "cgilib.h"

extern int  bvbar, dbug;

/*****************************************************************************/
/*
*/

int pass2 (struct wasdoc_st *docptr)
{
   int  count = 0, error = 0;
   char  *h1ptr, *cptr, *sptr, *zptr;

   if (dbug==1)
   {
      fputs (docptr->html, stdout);
      return (error);
   }

   if (dbug>2) dbugThis (FI_LI, "pass2()");

   if (docptr->insight >= 5) wasDocInsight (docptr, "second pass");

   if (dbug>2) dbugThis (FI_LI, "1~~~~~~~~~~\n%s~~~~~~~~~~1\n", docptr->html);

   /* put the first pass HTML into ->html1 */
   wasDocHtmlShuffle (docptr);

   pass2list (docptr);

   if (!docptr->title[0])
   {
      /* title not explicitly set so use first heading */
      cptr = pass2entry (docptr->list, 3);
      cptr = pass2strip (cptr);
      zptr = (sptr = docptr->title) + sizeof(docptr->title)-1;
      while (*cptr && sptr < zptr) *sptr++ = *cptr++;
      *sptr = '\0';
   }

   /* initialise the second pass HTML output buffer */
   wasDocMoreHtml (docptr);

   h1ptr = docptr->html1;
   while (*h1ptr)
   {
      zptr = (sptr = docptr->html) + docptr->hsize;
      sptr += docptr->hlength;
      while (*h1ptr && !MATCH6(h1ptr,"<!--$$") && sptr < zptr)
         *sptr++ = *h1ptr++;
      docptr->hlength = sptr - docptr->html;
      if (!*h1ptr) break;
      if (HMORE(docptr))
      {
         wasDocMoreHtml (docptr);
         continue;
      }
      count = pass2dollar2 (docptr, h1ptr);
      if (count < 0) break;
      h1ptr += count;
   }              

   if (count < 0) return (count);

   if (docptr->setNavigate) pass2navigate (docptr, docptr->finalH1);

   if (docptr->title[0])
      wasDocPrintf (docptr, "<title>%s</title>\n", docptr->title);
   else
   {
      cptr = pass2entry (docptr->list, 3);
      wasDocPrintf (docptr, "<title>%s</title>\n", cptr);
   }

   if (dbug>2) dbugThis (FI_LI, "2~~~~~~~~~~\n%s~~~~~~~~~~2\n", docptr->html);

   return (error);
}

/*****************************************************************************/
/*
Hit a '$$' in first pass HTML.  The '$$" are placed inside of HTML comments to
obscure the data when reporting errors.
*/

int pass2dollar2 (struct wasdoc_st *docptr, char *h1ptr)
{
   int  count;

   if (dbug>2) dbugThis (FI_LI, "pass2dollar2() %s", dbugMax(h1ptr));

   if (MATCH8 (h1ptr, "<!--$$H:"))
      count = pass2heading (docptr, h1ptr);
   else
   if (MATCH8 (h1ptr, "<!--$$L:"))
      count = pass2link (docptr, h1ptr);
   else
   if (MATCH8 (h1ptr, "<!--$$X:"))
      count = pass2extra (docptr, h1ptr);
   else
   if (MATCH12 (h1ptr, "<!--$$IDX$$-->"))
   {
      pass2idx (docptr);
      count = 14;
   }
   else
   if (MATCH12 (h1ptr, "<!--$$TOC$$-->"))
   {
      pass2toc1 (docptr);
      count = 14;
   }
   else
      wasDocBugcheck(FI_LI);

   return (count);
}

/*****************************************************************************/
/*
Heading data to be populated.
*/

int pass2heading (struct wasdoc_st *docptr, char *h1ptr)
{
   static char sigNumId [48];

   int  count, error, offset, numeric, section;
   char  *cptr, *lptr, *sptr, *zptr;
   char  numid [48];

   if (dbug>1) dbugThis (FI_LI, "pass2heading() %s", dbugMax(h1ptr));

   zptr = (sptr = numid) + sizeof(numid)-1;
   for (cptr = h1ptr + 8;
        *cptr && *cptr != '$' && sptr < zptr;
        *sptr++ = *cptr++);
   *sptr = '\0';
   if (!MATCH5(cptr,"$$-->") || sptr >= zptr) wasDocBugcheck(FI_LI);
   sptr = (cptr += 5);

   count = pass2find (docptr, numid);
   if (count < 0)
   {
      docptr->errorValue = SS$_NOSUCHOBJECT;
      RETURN_FI_LI (docptr, -1)
   }
   lptr = docptr->list + count;

   numeric = pass2numeric (numid);
   section = atoi(numid);
   if (section < atoi(sigNumId)) strcpy (sigNumId, numid);

   if (numeric == 1)
      if (section >= 0)
      {
         if (docptr->chunked > 0)
            if (docptr->setNavigate)
               pass2navigate (docptr, section-1);
         if (section >= 1)
            if (docptr->chunked <= 0)
               if (docptr->setPaginate)
                  wasDocAsIs (docptr, "<hr class=\"page\">\n");
      }

   /* note the beginning of this section's HTML */
   offset = docptr->hlength;

   /* numeric target ID */
   error = wasDocPrintf (docptr, "<a id=\"%s\" href=\"#\"></a>\n", numid); 
   if (error) wasDocBugcheck(FI_LI);

   /* step to the alphanumeric ID */
   count = *lptr++;
   lptr += count + 1;
   count = *lptr++;

   /* heading numeric plus alphanumeric ID */
   error = wasDocPrintf (docptr, "<a id=\"%s\" href=\"#\"></a>\n",
                         pass2linkid(numid,lptr)); 
   if (error) wasDocBugcheck(FI_LI);

   /* alphanumeric target ID */
   error = wasDocPrintf (docptr, "<a id=\"%s\" href=\"#\"></a>\n", lptr); 
   if (error) wasDocBugcheck(FI_LI);

   if (numeric == 1)
      if (section > 0)
         if (docptr->chunked)
            if (docptr->title[0])
            {
               error = wasDocPrintf (docptr,
"<h1 class=\"head chunk\">%s</h1>\n",
                                     docptr->title);
               if (error) wasDocBugcheck(FI_LI);
            }

   /* step to the description */
   lptr += count + 1;
   count = *lptr++;

   if (!MATCH2(cptr,"<h")) wasDocBugcheck(FI_LI);
   if (!isdigit(cptr[2])) wasDocBugcheck(FI_LI);
   if (cptr[3] != ' ') wasDocBugcheck(FI_LI);
   sptr = cptr;
   for (cptr += 4; *cptr && *cptr != '>'; cptr++);
   if (!*cptr) wasDocBugcheck(FI_LI);
   cptr++;

   /* insert heading tag including class, style, etc. */
   error = wasDocPrintf (docptr, "%*.*s", cptr-sptr, cptr-sptr, sptr);
   if (error) wasDocBugcheck(FI_LI);

   if (numeric <= 4)
      error = wasDocPrintf (docptr,
"<span class=\"numb\">%s</span><span class=\"text\">%s</span>",
                            numid, lptr); 
   else
      error = wasDocPrintf (docptr,
"<span class=\"text\">%s</span>",
                            lptr); 
   if (error) wasDocBugcheck(FI_LI);

   /* step to the offset longword and record it */
   lptr += count + 1;
   *(ULONGPTR)lptr = offset;

   while (*cptr && !MATCH3(cptr,"</h")) cptr++;
   if (!*cptr) wasDocBugcheck(FI_LI);
   if (!isdigit(cptr[3])) wasDocBugcheck(FI_LI);
   if (cptr[4] != '>') wasDocBugcheck(FI_LI);
   sptr = cptr;
   cptr += 5;
   if (*cptr == '\n') cptr++;

   error = wasDocPrintf (docptr, "%*.*s", cptr-sptr, cptr-sptr, sptr); 
   if (error) wasDocBugcheck(FI_LI);

   if (numeric == 1)
   {
      if (docptr->setToc2) pass2toc2 (docptr, numid);
      if (docptr->setNavigate) pass2navigate (docptr, section);
   }

   return (cptr - h1ptr);
}

/*****************************************************************************/
/*
Insert a link to another part of the document.
*/

int pass2link (struct wasdoc_st *docptr, char *h1ptr)
{
   int  count, numeric, section;
   char  *aptr, *cptr, *lptr, *nptr, *sptr, *zptr;
   char  buf [256];

   if (dbug>2) dbugThis (FI_LI, "pass2link() %s", dbugMax(h1ptr));

   /* error report (will be emptied if there is not an error) */
   zptr = (sptr = docptr->pass2At) + sizeof(docptr->pass2At)-1;
   /* "<!--$$L:" */
   for (cptr = h1ptr + 8;
        *cptr && !MATCH2(cptr,"$#") && sptr < zptr;
        *sptr++ = *cptr++);
   *sptr = '\0';
   if (!MATCH2(cptr,"$#") || sptr >= zptr) wasDocBugcheck(FI_LI);

   /* find this heading */
   zptr = (sptr = buf) + sizeof(buf)-1;
   for (cptr += 2;
        *cptr && *cptr != '$' && sptr < zptr;
        *sptr++ = *cptr++);
   *sptr = '\0';
   if (!MATCH5(cptr,"$$-->") || sptr >= zptr) wasDocBugcheck(FI_LI);
   aptr = (cptr += 5);

   count = pass2find (docptr, buf);
   if (count < 0)
   {
      /* see renderInsertLink() */
      cptr = strstr (docptr->pass2At, "&quot;") + 6;
      sptr = strstr (cptr, "&quot;");
      wasDocPrintf (docptr, "\">%*.*s</a>", sptr-cptr, sptr-cptr, cptr);
      docptr->errorValue = SS$_NOSUCHOBJECT;
      RETURN_FI_LI (docptr, -1)
   }
   docptr->pass2At[0] = '\0';

   lptr = docptr->list + count;
   count = *lptr++;

   /* nptr now points to the numeric ID */
   nptr = lptr;
   section = atoi(nptr);
   numeric = pass2numeric (nptr);

   /* and lptr to the alphanumeric ID */
   lptr += count + 1;
   count = *lptr++;
   wasDocPrintf (docptr, "%s#%s",
                 pass2chunk(docptr,section), pass2linkid(nptr,lptr)); 

   if (MATCH6 (aptr, "\"></a>"))
   {
      /* empty, so use the heading description */
      aptr += 6;
      lptr += count + 1;
      count = *lptr++;
      if (numeric <= 4)
         wasDocPrintf (docptr, "\">%s %s</a>", nptr, pass2strip(lptr)); 
      else
         wasDocPrintf (docptr, "\">%s</a>", pass2foundin(docptr,nptr)); 
   }

   return (aptr - h1ptr);
}

/*****************************************************************************/
/*
Do something else during the second pass.
*/

int pass2extra (struct wasdoc_st *docptr, char *h1ptr)
{
   int  number;
   char  *aptr, *cptr, *sptr, *zptr;
   char  buf [256];

   if (dbug>2) dbugThis (FI_LI, "pass2extra() %s", dbugMax(h1ptr));

   zptr = (sptr = buf) + sizeof(buf)-1;
   for (cptr = h1ptr + 8;
        *cptr && *cptr != '$' && sptr < zptr;
        *sptr++ = *cptr++);
   *sptr = '\0';
   if (!MATCH5(cptr,"$$-->") || sptr >= zptr) wasDocBugcheck(FI_LI);
   aptr = cptr + 5;

   if (MATCH12 (buf, "toc2=next=cols="))
   {
      number = atoi(cptr = buf + 15);
      docptr->setToc2NextCols = number;
      while (*cptr && isdigit(*cptr)) cptr++;
      while (*cptr && !isdigit(*cptr)) cptr++;
      if (isdigit(*cptr))
         if ((number = atoi(cptr)) <= 100)
            docptr->setToc2NextColsWidth = number;
   }

   return (aptr - h1ptr);
}

/*****************************************************************************/
/*
This creates an in-memory list of heading numeric IDs, with alphanumeric IDs,
and heading text.  The format

   <uchar>string<nul><uchar>string<nul><uchar>string<nul><ulong>

where <uchar> is the count byte (0..255) and string is the counted string.  The
string IS ALSO null-terminated allowing direct use as a null-terminated
"string".  The final <ulong> is an offset into the final HTML document.  List
is terminated by a <uchar> of zero.  So a maximal list entry is three lots of
maximum 255 character plus null-termination counted-strings plus one ulong.
*/

void pass2list (struct wasdoc_st *docptr)
{
   int  count;
   char  *cptr, *h1ptr, *sptr, *zptr;
   uchar  *lptr;
   char  buf [256];

   if (dbug>1) dbugThis (FI_LI, "pass2list()");

   h1ptr = docptr->html1;

   while (*h1ptr)
   {
      if (docptr->list) docptr->llength = (char*)lptr - docptr->list;
      if (docptr->lsize - docptr->llength <= ((1+255+1) * 3) + sizeof(uint))
      {
         docptr->lsize += LIST_INCREMENT;
         docptr->list = realloc (docptr->list, docptr->lsize);
         if (!docptr->list) EXIT_FI_LI (vaxc$errno);
         lptr = (uchar*)docptr->list + docptr->llength;
      }

      /* insert numeric ID */
      while (*h1ptr && !MATCH4(h1ptr,"$$H:")) h1ptr++;
      if (!*h1ptr) break;
      for (cptr = sptr = h1ptr + 4; *cptr && *cptr != '$'; cptr++);
      if (!MATCH5(cptr,"$$-->")) wasDocBugcheck(FI_LI);
      /* eventually it will be! */
      docptr->finalH1 = atoi(sptr);
      count = cptr - sptr;
      cptr += 5;
      *lptr++ = count;
      while (count-- > 0) *lptr++ = *sptr++;
      *lptr++ = '\0';

      /* insert alphanumeric ID */
      if (!MATCH2(cptr,"<h")) wasDocBugcheck(FI_LI);
      while (*cptr && *cptr != '>') cptr++;
      if (!*cptr) wasDocBugcheck(FI_LI);
      cptr++;
      /* absorb leading white-space */
      while (*cptr && isspace(*cptr)) cptr++;
      /* note the start of the heading text */
      h1ptr = cptr;
      zptr = (sptr = buf) + sizeof(buf)-1;
      while (*cptr && !MATCH3(cptr,"</h") && sptr < zptr)
      {
         if (*cptr == '<')
         {
            /* excise any highlight HTML */
            cptr++;
            while (*cptr && *cptr != '>') cptr++;
            if (!*cptr) break;
            cptr++;
            continue;
         }
         if (!isalnum(*cptr))
         {
            cptr++;
            continue;
         }
         *sptr++ = tolower(*cptr++);
      }
      *sptr = '\0';
      if (!*cptr || sptr >= zptr) wasDocBugcheck(FI_LI);
      /* absorb trailing white-space */
      while (sptr > buf && isspace(*(sptr-1))) sptr--;
      count = sptr - buf;
      /* if the heading contained no alphanumerics */
      if (!count)
      {
         strcpy (buf, "-empty-");
         count = 7;
      }
      *lptr++ = count;
      for (sptr = buf; *sptr; *lptr++ = *sptr++);
      *lptr++ = '\0';

      /* insert heading text */
      cptr = h1ptr;
      zptr = (sptr = buf) + sizeof(buf)-1;
      while (*cptr && !MATCH3(cptr,"</h") && sptr < zptr)
      {
         if (iscntrl(*cptr))
            *sptr++ = ' ';
         else
            *sptr++ = *cptr;
         cptr++;
      }
      *sptr = '\0';
      if (!*cptr) wasDocBugcheck(FI_LI);
      if (sptr >= zptr)
      {
         /* overly long heading text is truncated - scissors to indicate */
         strcpy (sptr-8, "&#9986;");
         while (*cptr && !MATCH3(cptr,"</h")) cptr++;
      }
      /* note the end of the heading description */
      h1ptr = cptr + sizeof("</h*>")-1;
      count = sptr - buf;
      if (!count)
      {
         strcpy (buf, "&rarr; EMPTY HEADING &larr;");
         count = 27;
      }
      *lptr++ = count;
      for (sptr = buf; *sptr; *lptr++ = *sptr++);
      *lptr++ = '\0';

      /* space for the offset */
      *(ULONGPTR)lptr = 0;
      lptr += sizeof(ulong);
   }

   /* terminate the list with a zero length entry (and a bit t'be sure) */
   *(ULONGPTR)lptr = 0;

   if (dbug>1) pass2dlist (docptr);
}

/*****************************************************************************/
/*
Debug report on ->list content.
*/

void pass2dlist (struct wasdoc_st *docptr)
{
   int  count, count1, count2, count3, offset;
   uchar  *lptr, *lptr1, *lptr2, *lptr3;

   dbugThis (FI_LI, "pass2dlist() %d/%d", docptr->llength, docptr->lsize);
   lptr = (uchar*)docptr->list;
   count = 0;
   for (;;)
   {
      count1 = *lptr++;
      if (!count1) break;
      lptr1 = lptr;
      lptr += count1 + 1;
      count2 = *lptr++;
      lptr2 = lptr;
      lptr += count2 + 1;
      count3 = *lptr++;
      lptr3 = lptr;
      lptr += count3 + 1;
      offset = *(ULONGPTR)lptr;
      lptr += sizeof(ulong);
      count++;
      dbugThis (NULL, 0, "%d %d%c%s%c %d%c%s%c %d%c%s%c %d",
                count, count1, bvbar, lptr1, bvbar,
                       count2, bvbar, lptr2, bvbar,
                       count3, bvbar, lptr3, bvbar, offset);
   }
}

/*****************************************************************************/
/*
*/

void pass2offset (struct wasdoc_st *docptr)
{
   int  count;
   char  *cptr, *h1ptr, *sptr, *zptr;
   uchar  *lptr;
   char  buf [256];

   if (dbug>1) dbugThis (FI_LI, "pass2offset()");
}

/*****************************************************************************/
/*
Return a string stripped of HTML tags from the heading descriptor.
*/

char* pass2strip (char *cptr)
{
   static char  buf [256];
   char  *sptr, *zptr;

   while (isspace(*cptr)) cptr++;
   zptr = (sptr = buf) + sizeof(buf)-1;
   while (*cptr && sptr < zptr)
   {
      if (*cptr != '<')
      {
         *sptr++ = *cptr++;
         continue;
      }
      cptr++;
      while (*cptr != '>') cptr++;
      if (*cptr) cptr++;
   }
   *sptr = '\0';
   return (buf);
}

/*****************************************************************************/
/*
Finding returns the offset from the start of the list, or the  if not found.
*/

int pass2find (struct wasdoc_st *docptr, char *find)
{
   uint  count, flen, flength, numeric;
   char  *cptr, *sptr;
   uchar  *lptr;

   if (dbug>2) dbugThis (FI_LI, "pass2find() %s", dbugAll(find));

   /* is a numeric ID being searched for? (n.n.n.n.n.n) */
   for (cptr = find; *cptr && (isdigit(*cptr) || *cptr == '.'); cptr++);
   numeric = ((cptr > find) && !*cptr);
   if (!numeric) for (cptr = find; *cptr; cptr++);
   flength = cptr - find;

   if (!flength) return (0);

   lptr = (uchar*)docptr->list; 
   for (;;)
   {
      /* note the start of entry */
      sptr = (char*)lptr;
      /* length of numeric ID */
      count = *lptr++;
      /* if end of list */
      if (!count) break;
      cptr = find;
      flen = flength;
      if (numeric)
      {
         /* compare the numeric ID */
         if (count == flen)
            while (count && flen && *lptr == *cptr)
               { count--; flen--; lptr++; cptr++; }
         if (!count && !flen) break;
         /* step over remainder, then alphanumeric, then text */
         lptr += count + 1;
         count = *lptr++;
         lptr += count + 1;
         count = *lptr++;
         lptr += count + 1;
         lptr += sizeof(ulong);
      }
      else
      {
         /* step over the numeric ID */
         lptr += count + 1;
         /* compare the alphanumeric ID */
         count = *lptr++;
         if (count == flen)
            while (count && flen && *lptr == *cptr)
               { count--; flen--; lptr++; cptr++; }
         if (!count && !flen) break;
         /* step over remainder, then text */
         lptr += count + 1;
         count = *lptr++;
         lptr += count + 1;
         lptr += sizeof(ulong);
      }
   }

   if (count || flen) return (-1);
   return (sptr - docptr->list);
}

/*****************************************************************************/
/*
Given a pointer to the list entry, and 1 for the numeric identifier, 2 for the
alphanumeric identifier, 3 for the heading description, return the value in a
static buffer.
*/

char* pass2entry (char *lptr, int which)
{
   static char  buf [256];
   int  count;
   char  *cptr, *sptr;

   if (which < 1 || which > 3) wasDocBugcheck(FI_LI);
   count = *lptr++;
   if (!count || count > 24) wasDocBugcheck(FI_LI);
   if (which > 1)
   {
      lptr += count + 1;
      count = *lptr++;
      if (!count || count > 255) wasDocBugcheck(FI_LI);
      if (which > 2)
      {
         lptr += count + 1;
         count = *lptr++;
         if (!count || count > 255) wasDocBugcheck(FI_LI);
      }
   }
   for (sptr = buf; count--; *sptr++ = *lptr++);
   *sptr = '\0';
   return (buf);
}

/*****************************************************************************/
/*
Return a pointer to the next entry in the heading list.
*/

char* pass2next (char *lptr)
{
   int  count;

   count = *lptr++;
   if (!count || count > 24) wasDocBugcheck(FI_LI);
   lptr += count + 1;
   count = *lptr++;
   if (!count || count > 255) wasDocBugcheck(FI_LI);
   lptr += count + 1;
   count = *lptr++;
   if (!count || count > 255) wasDocBugcheck(FI_LI);
   lptr += count + 1;
   lptr += sizeof(ulong);
   return (lptr);
}

/*****************************************************************************/
/*
Generate a primary Table of Content using the heading list.
A primary TOC includes all <h1>..<h4> headings.
*/

int pass2toc1 (struct wasdoc_st *docptr)
{
   int  count, error = 0, numeric, section, total = 0;
   char  *lptr, *lptr1, *lptr2, *lptr3, *sptr;

   if (dbug>1) dbugThis (FI_LI, "pass2toc1()");

   lptr = docptr->list;

   for (;;)
   {
      lptr1 = lptr;
      /* point to the numeric ID */
      count = *lptr1++;
      if (!count) break;
      /* point to the alphanumeric ID */
      lptr2 = lptr1 + count + 1;
      count = *lptr2++;
      /* point to the heading description */
      lptr3 = lptr2 + count + 1;
      count = *lptr3++;
      /* point at the next entry */
      lptr = lptr3 + count + 1 + sizeof(ulong);

      numeric = pass2numeric (lptr1);
      if (numeric > 4) continue;
      section = atoi(lptr1);

      if (!total++)
      {
         error = wasDocPrintf (docptr,
"\n<div class=\"TOC1cols%d\">\n\
<table class=\"TOC1table\">\n",
                                docptr->setTocCols);
         if (error) RETURN_FI_LI (docptr, error);
      }

      if (docptr->setTocForm[0] >= '1' &&
          docptr->setTocForm[0] <= '9')
      {
         if (docptr->setTocForm[1])
            /* numbering and heading separated by repeated characters */
            error = wasDocPrintf (docptr,
"<tr><td class=\"sepr\"><a href=\"%s#%s\">%s</a>%s\
<td class=\"text%s\"><a href=\"%s#%s\">%s</a>\n",
                          pass2chunk(docptr,section),
                          pass2linkid(lptr1,lptr2), lptr1,
                          docptr->setTocForm+1,
                          numeric == 1 ? " majr" : "",
                          pass2chunk(docptr,section),
                          pass2linkid(lptr1,lptr2), lptr3);
         else
            /* just empty space */
            error = wasDocPrintf (docptr,
"<tr><td class=\"numb\"><a href=\"%s#%s\">%s</a>\
<td class=\"text%s\"><a href=\"%s#%s\">%s</a>\n",
                          pass2chunk(docptr,section),
                          pass2linkid(lptr1,lptr2), lptr1,
                          numeric == 1 ? " majr" : "",
                          pass2chunk(docptr,section),
                          pass2linkid(lptr1,lptr2), lptr3);
      }
      else
         /* anything else (e.g. HTML entity) is just used as-is */
         error = wasDocPrintf (docptr,
"<tr><td class=\"text%s\"><a href=\"%s#%s\">%s%s</a>\n",
                          numeric == 1 ? " majr" : "",
                          pass2chunk(docptr,section),
                          pass2linkid(lptr1,lptr2),
                          docptr->setTocForm, lptr3);

      if (error) RETURN_FI_LI (docptr, error);
   }

   if (total) wasDocAsIs (docptr, "</table>\n</div>\n");

   return (error);
}

/*****************************************************************************/
/*
Generate a secondary (sub-)TOC after each <h1> using the heading list.
*/

int pass2toc2 (struct wasdoc_st *docptr, char *numid)
{
   int  cols, count, digit1, error = 0,
        numeric, section, subtotal = 0, total = 0;
   char  *cptr, *lptr, *lptr1, *lptr2, *lptr3, *sptr;
   char  width [64];

   if (dbug>1) dbugThis (FI_LI, "pass2toc2() %s", dbugAll(numid));

   if (!docptr->setToc2) return (0);

   count = pass2find (docptr, numid);
   if (count < 0) RETURN_FI_LI (docptr, count)
   lptr = docptr->list + count;
   digit1 = atoi (numid);

   /* determine how many subsections */
   lptr1 = lptr;
   for (;;)
   {
      count = *lptr1++;
      if (!count) break;
      if (atoi(lptr1) != digit1) break;
      numeric = pass2numeric (lptr1);
      if (numeric > 1 && numeric <= 4) subtotal++;
      lptr1 += count + 1;
      count = *lptr1++;
      lptr1 += count + 1;
      count = *lptr1++;
      lptr1 += count + 1;
      lptr1 += sizeof(ulong);
   }

   for (;;)
   {
      lptr1 = lptr;
      /* point to the numeric ID */
      count = *lptr1++;
      if (!count) break;
      if (atoi(lptr1) != digit1) break;
      /* point to the alphanumeric ID */
      lptr2 = lptr1 + count + 1;
      count = *lptr2++;
      /* point to the heading description */
      lptr3 = lptr2 + count + 1;
      count = *lptr3++;
      /* point at the next entry */
      lptr = lptr3 + count + 1 + sizeof(ulong);

      numeric = pass2numeric (lptr1);
      if (numeric == 1) continue;
      if (docptr->setToc2 == 1 && numeric > 4) continue;
      section = atoi(lptr1);

      if (!total++)
      {
         if (subtotal > 4)
         {
            if (docptr->setToc2NextColsWidth)
               sprintf (width, " style=\"width:%d%%;max-width:%d%%;\"",
                        docptr->setToc2NextColsWidth,
                        docptr->setToc2NextColsWidth);
            else
            if (docptr->setToc2ColsWidth)
               sprintf (width, " style=\"width:%d%%;max-width:%d%%;\"",
                        docptr->setToc2ColsWidth,
                        docptr->setToc2ColsWidth);
            else
               width[0] = '\0';

            if (!(cols = docptr->setToc2NextCols)) cols = docptr->setToc2Cols;

            error = wasDocPrintf (docptr,
"\n<div class=\"TOC2cols%d\"%s>\n\
<table class=\"TOC2table\">\n", cols, width);
         }
         else
            error = wasDocPrintf (docptr, "\n<table class=\"TOC2table\">\n");
         if (error) RETURN_FI_LI (docptr, error);

         docptr->setToc2NextCols = docptr->setToc2NextColsWidth = 0;
      }

      if (numeric <= 4)
         error = wasDocPrintf (docptr,
"<tr><td><a href=\"%s#%s\">\
<span class=\"numb\">%s</span>\
<span class=\"text\">%s</span></a>\n",
                               pass2chunk(docptr,section),
                               pass2linkid(lptr1,lptr2),
                               lptr1, pass2strip(lptr3));
      else
         error = wasDocPrintf (docptr,
"<tr><td><a href=\"%s#%s\"><span class=\"text\">%s</span></a>\n",
                               pass2chunk(docptr,section),
                               pass2linkid(lptr1,lptr2),
                               pass2strip(lptr3));

      if (error) RETURN_FI_LI (docptr, error);
   }

   if (total) wasDocAsIs (docptr, "</table>\n</div>\n");

   return (error);
}

/*****************************************************************************/
/*
Return true if the fifth or sixth integer is the "suppress index entry"
sentinal.
*/

int pass2noidx (char *cptr)
{
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   if (atoi(cptr) == SECTION_NO_INDEX) return (1);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   return (atoi(cptr) == SECTION_NO_INDEX);
}

/*****************************************************************************/
/*
Return true if the fifth or sixth integer is the not "'heading' in section"
sentinal.
*/

int pass2notin (char *cptr)
{
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   if (atoi(cptr) == SECTION_NOT_IN) return (1);
   while (isdigit(*cptr)) cptr++;
   if (*cptr++ != '.') return (0);
   return (atoi(cptr) == SECTION_NOT_IN);
}

/*****************************************************************************/
/*
Generate the document index using the heading list.
Use this pass to set the <ulong> offset into the final HTML.
*/

int pass2idx (struct wasdoc_st *docptr)
{
   static char sigNumId [48];

   int  count, entries = 0, error = 0, idx, numeric, section, total = 0;
   char  *abc, *cptr, *dptr, *lptr, *lptr1, *lptr2, *lptr3, *sptr, *zptr;
   char  alpha[16] = "";
   char  **sarray;

   if (dbug>1) dbugThis (FI_LI, "pass2idx()");

   abc = docptr->idxCollate;
   for (idx = 0;; idx += 2)
   {
      if (!abc[idx]) break;
      alpha[0] = abc[idx];
      if (alpha[0] == '0')
         /* Combining Short Solidus Overlay turn zero into slash-zero */
         strcpy (alpha, "0&#x0337;");
      else
         alpha[1] = '\0';
      if (dbug>2) dbugThis (FI_LI, "%c%c%c", bvbar, abc[idx], bvbar);

      /* total the number of entries matching the collate character */
      lptr = docptr->list;
      for (total = 0;;)
      {
         count = *lptr++;
         if (!count) break;
         lptr1 = lptr;
         lptr += count + 1;
         count = *lptr++;
         lptr += count + 1;
         count = *lptr++;
         if (*(cptr = lptr) == '&')
         {
            /* step over HTML-entified characters */
            for (cptr++; *cptr && isalnum(*cptr); cptr++);
            if (*cptr == ';') cptr++; else cptr = lptr;
         }
         /* if not this "suppress index entry" sentinal */
         if (!pass2noidx (lptr1))
            /* match first character of heading description */
            if (*cptr == abc[idx] || *cptr == abc[idx+1])
               total++;
         lptr += count + 1 + sizeof(ulong);
      }

      /* allocate a suitably sized sort array of pointers */
      sarray = calloc (total + 1, sizeof(char*));
      if (!sarray) exit (vaxc$errno);

      /* populate the array of pointers */
      lptr = docptr->list;
      for (total = 0;;)
      {
         /* note the current list entry */
         sarray[total] = lptr;
         count = *lptr++;
         if (!count) break;
         lptr1 = lptr;
         lptr += count + 1;
         count = *lptr++;
         lptr += count + 1;
         count = *lptr++;
         if (*(cptr = lptr) == '&')
         {
            /* step over HTML-entified characters */
            for (cptr++; *cptr && isalnum(*cptr); cptr++);
            if (*cptr == ';') cptr++; else cptr = lptr;
         }
         /* if not this "suppress index entry" sentinal */
         if (!pass2noidx (lptr1))
            /* if matches increment to the next sort array element */
            if (*cptr == abc[idx] || *cptr == abc[idx+1])
               total++;
         lptr += count + 1 + sizeof(ulong);
      }
      /* NULL the final element */
      sarray[total] = NULL;

      /* sort the array */
      if (docptr->setIdxSort) qsort (sarray, total, sizeof(char*), pass2isort);

      /* output the (sorted) array */
      for (total = 0; sarray[total]; total++)
      {
         if (!entries++)
         {
            error = wasDocPrintf (docptr,
"<div class=\"IDXcols%d\">\n\
<table class=\"IDXtable\">\n",
                                  docptr->setIdxCols);
            if (error) RETURN_FI_LI (docptr, error);
         }

         lptr1 = sarray[total];
         count = *lptr1++;
         lptr2 = lptr1 + count + 1;
         count = *lptr2++;
         lptr3 = lptr2 + count + 1;
         lptr3++;

         section = atoi(lptr1);
         numeric = pass2numeric (lptr1);

         if (dbug>2) dbugThis (FI_LI, "%d %c%s%c %c%s%c %c%s%c",
                               numeric,
                               bvbar, lptr1, bvbar,
                               bvbar, lptr2, bvbar,
                               bvbar, lptr3, bvbar);
         if (numeric <= 4)
         {
            error = wasDocPrintf (docptr,
"<tr><td class=\"alpha\">%s</td>\
<td class=\"text\">\
<a href=\"%s#%s\">%s&nbsp;%s</a>\n",
                                  alpha,
                                  pass2chunk(docptr,section),
                                  pass2linkid(lptr1,lptr2),
                                  lptr1, pass2strip(lptr3));
            if (error) RETURN_FI_LI (docptr, error);
         }
         else
         if (pass2notin (lptr1))
         {
            error = wasDocPrintf (docptr,
"<tr><td class=\"alpha\">%s</td>\
<td class=\"text\">\
<a href=\"%s#%s\">%s</a>\n",
                                  alpha,
                                  pass2chunk(docptr,section),
                                  pass2linkid(lptr1,lptr2),
                                  pass2strip(lptr3));
            if (error) RETURN_FI_LI (docptr, error);
         }
         else
         { 
            error = wasDocPrintf (docptr,
"<tr><td class=\"alpha\">%s</td>\
<td class=\"text\"><a href=\"%s#%s\">%s</a>\n",
                                  alpha,
                                  pass2chunk(docptr,section),
                                  pass2linkid(lptr1,lptr2),
                                  pass2foundin(docptr,lptr1));
            if (error) RETURN_FI_LI (docptr, error);
         }

         if (alpha[0] != '&') strcpy (alpha, "&nbsp;");
      }

      free (sarray);
   }

   if (entries) wasDocAsIs (docptr, "</table>\n</div>\n"); 

   return (error);
}

/*****************************************************************************/
/*
Comparison function for pass2idx() qsort().
The heading description strings are compared non-case-sensitive.
*/

int pass2isort (const void *a, const void *b)
{
   int  count;
   char  *aptr, *bptr;

   aptr = *((char**)a);
   count = *aptr++;
   aptr += count + 1;
   count = *aptr++;
   aptr += count + 2;

   bptr = *((char**)b);
   count = *bptr++;
   bptr += count + 1;
   count = *bptr++;
   bptr += count + 2;

   return (strcasecmp (aptr, bptr));
}

/*****************************************************************************/
/*
<back> <previous> <top> <next> <forward>
*/

void pass2navigate
(
struct wasdoc_st *docptr,
int section
)
{
   if (dbug>1) dbugThis (FI_LI, "pass2navigate(%d)", section);

   if (!docptr->setNavigate) return;

   wasDocPrintf (docptr,
"\n<table class=\"NAVtable%s\"><tr>\n\
<td><a href=\"javascript:window.history.back();\">%s</a>\n",
                 docptr->setNavigate > 1 ? " NAVprint" : "",
                 docptr->iconBack);
   if (section > 0)
   {
      wasDocPrintf (docptr, "<td><a href=\"%s#%d.\">%s</a>\n",
                    pass2chunk(docptr,section-1), section-1,
                    docptr->iconPrev);
      wasDocPrintf (docptr, "<td><a href=\"%s#0.\">%s</a>\n",
                    pass2chunk(docptr,0),
                    docptr->iconTop);
   }
   else
      wasDocPrintf (docptr, "<td><a>%s</a>\n<td><a>%s</a>\n",
                     docptr->iconPrev, docptr->iconTop);


   if (section < docptr->finalH1)
      wasDocPrintf (docptr, "<td><a href=\"%s#%d.\">%s</a>\n",
                    pass2chunk(docptr,section+1), section+1,
                    docptr->iconNext);
   else
      wasDocPrintf (docptr, "<td><a>%s</a>\n", docptr->iconNext);

   wasDocPrintf (docptr,
"<td><a href=\"javascript:window.history.forward();\">%s</a>\n\
</table>\n",
                  docptr->iconForw);
}

/*****************************************************************************/
/*
Chunked wasDOC is where the client is provided with only one major section
(<h1>) at a time.  This is a three digit pseudo-section appended to the path,
leading zeroes as required.  This function creates a unique path that includes
a "chunk" number based on the leading fragment ID integer so that the browser
requests using that path keeping all the (global) fragment IDs viable.

This function is NOT REENTRANT and must be used at most ONCE per print.
*/

char* pass2chunk
(
struct wasdoc_st *docptr,
int number
)
{
   static char  path [256];
   int  cnt = 0;
   char  *cptr, *sptr, *zptr;

   if (dbug>1) dbugThis (FI_LI, "pass2chunk() %d", number);

   if (docptr->chunked <= 0) return ("");

   zptr = (sptr = path) + sizeof(path)-16;
   if (docptr->oname[0])
   {
      /* output to file(s) */
      for (cptr = docptr->oname; *cptr && sptr < zptr; *sptr++ = *cptr++);
      sptr += sprintf (sptr, "%03.3d.html", number);
   }
   else
   {
      /* output via script */
      for (cptr = docptr->uri; *cptr && sptr < zptr; *sptr++ = *cptr++);
      if (*(cptr-1) != '/' && sptr < zptr) *sptr++ = '/';
      sptr += sprintf (sptr, "%03.3d", number);
      if (sptr < zptr) *sptr++ = '/';
   }
   *sptr = '\0';

   return (path);
}

/*****************************************************************************/
/*
Where a non-major heading (5 and 6) create a link description that provides
what section the heading is found in.  |lptr1| points to the numeric ID. 
Return a pointer to a static buffer containing the description.
*/

char* pass2foundin (struct wasdoc_st *docptr, char *lptr1)
{
   static char  buf [256];

   int  count;
   char  *cptr, *lptr, *lptr2, *lptr3, *sptr, *zptr;

   lptr = lptr1 - 1;
   count = *lptr++;
   lptr += count + 1;
   count = *lptr++;
   lptr2 = lptr;
   lptr += count + 1;
   count = *lptr++;
   lptr3 = lptr;

   zptr = (sptr = buf) + sizeof(buf)-1;
   for (cptr = "&lsquo;"; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = pass2strip(lptr3);
        *cptr && sptr < zptr;
        *sptr++ = *cptr++);
   for (cptr = "&rsquo;"; *cptr && sptr < zptr; *sptr++ = *cptr++);
   /* use the default heading */
   if (!*(cptr = docptr->setFoundIn)) cptr = DEFAULT_FOUND_IN;
   while (*cptr && sptr < zptr) *sptr++ = *cptr++;

   if (cptr = pass2parent (lptr1))
   {
      if (MATCH3 (cptr, "0."))
         cptr = docptr->title;
      else
      if ((count = pass2find (docptr, cptr)) >= 0)
      {
         lptr = docptr->list + count;
         count = *lptr++;
         /* the numeric ID */
         cptr = pass2parent (lptr);
         while (*cptr && sptr < zptr) *sptr++ = *cptr++;
         lptr += count + 1;
         count = *lptr++;
         lptr += count + 1;
         count = *lptr++;
         /* the heading description */
         cptr = pass2strip (lptr);
      }
      else
         cptr = "&quest;";
   }
   else
      cptr = "&iquest;";

   if (sptr < zptr) *sptr++ = ' ';
   while (*cptr && sptr < zptr) *sptr++ = *cptr++;
   *sptr = '\0';

   return (buf);
}

/*****************************************************************************/
/*
Parse out the "parent" up to four-integer numeric ID and return.
So, "8.0.0.0.0.2" becomes "8.", and  "8.1.0.0.1.0" becomes "8.1".
*/

char* pass2parent (char *numid)
{
   static char  buf [48];
   int  digit4 [1+4];
   char  *cptr;

   if (dbug>2) dbugThis (FI_LI, "pass2parent() |%s|", dbugAll(numid));

   digit4[1] = atoi (cptr = numid);
   while (isdigit(*cptr)) cptr++;
   if (*cptr) cptr++;
   digit4[2] = atoi (cptr);
   while (isdigit(*cptr)) cptr++;
   if (*cptr) cptr++;
   digit4[3] = atoi (cptr);
   while (isdigit(*cptr)) cptr++;
   if (*cptr) cptr++;
   digit4[4] = atoi (cptr);
   if (digit4[4])
      sprintf (buf, "%d.%d.%d.%d", digit4[1], digit4[2], digit4[3], digit4[4]);
   else
   if (digit4[3])
      sprintf (buf, "%d.%d.%d", digit4[1], digit4[2], digit4[3]);
   else
   if (digit4[2])
      sprintf (buf, "%d.%d", digit4[1], digit4[2]);
   else
      sprintf (buf, "%d.", digit4[1]);

   if (dbug>2) dbugThis (FI_LI, "%s", dbugAll(buf));
   return (buf);
}

/*****************************************************************************/
/*
Return a pointer to a static ID for a '<a id=".." href="#"></a>' anchor
target.  Numeric ID is always separated from alphanumeric by a period.
Examples: "0.alnumid", "8.alnumid", "8.1.alnumid".
*/

char* pass2linkid (char *numid, char *alnumid)
{
   static char  buf [256];
   char  *cptr, *sptr, *zptr;

   zptr = (sptr = buf) + sizeof(buf)-1;
   cptr = pass2parent (numid);
   while (*cptr && sptr < zptr) *sptr++ = *cptr++;
   if (*(sptr-1) != '.' && sptr < zptr) *sptr++ = '.';
   for (cptr = alnumid; *cptr && sptr < zptr; *sptr++ = *cptr++);
   *sptr = '\0';
   return (buf);
}

/*****************************************************************************/
/*
Return the number of section numbers represented by the numeric ID.
*/

int pass2numeric (char *numid)
{
   int numeric = 0;

   if (!isdigit(*numid)) return (0);
   while (*numid)
   {
      while (isdigit(*numid)) numid++;
      numeric++;
      if (!*numid) return (numeric);
      if (*numid != '.') return (0);
      numid++;
   }
   return (numeric);
}

/*****************************************************************************/