Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
trace-out.c
Go to the documentation of this file.
1 /* *************************************************************************************
2  Copyright (c) 2021, Lowell D. Thomas
3  All rights reserved.
4 
5  This file is part of APG Version 7.0.
6  APG Version 7.0 may be used under the terms of the BSD 2-Clause License.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10 
11  1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 
14  2. Redistributions in binary form must reproduce the above copyright notice,
15  this list of conditions and the following disclaimer in the documentation
16  and/or other materials provided with the distribution.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 * *************************************************************************************/
33 #include "./apg.h"
34 #ifdef APG_TRACE
35 #include "./lib.h"
36 #include "./parserp.h"
37 #include "./tracep.h"
38 static const aint s_uiMaxPhraseLength = 120;
39 static aint uiAcharToHex(achar acChar, char* cpHex);
40 static const char* cpIsControl(achar acChar);
41 static abool bIsUnicode(achar acChar);
42 static const char* s_caControlChars[33] =
43 {"NULL","SOH","STX","ETX","EOT","ENQ","ACK","BEL","BS","\\t",
44  "\\n","VT","FF","\\r","SO","SI","DLE","DC1","DC2","DC3",
45  "DC4","NAK","SYN","ETB","CAN","EM","SUB","ESC","FS","GS",
46  "RS","US","DEL"};
47 
51 typedef struct{
53  const achar* acpInput;
54  char* cpOutput;
57  char* cpEmpty;
58  char* cpLastChar;
59 } html_info;
60 static const char* s_cpHtmlHeader;
61 static const char* s_cpHtmlFooter;
62 
63 static void vAsciiPpptRecord(trace* spCtx, trace_record* spRec);
64 static void vHtmlPpptRecord(trace* spCtx, trace_record* spRec);
65 static void vHtmlHeader(trace* spCtx);
66 static void vHtmlSeparator(trace* spCtx, aint uiLastIndex);
67 static void vHtmlRecord(trace* spCtx, trace_record* spRec);
68 static void vHtmlFooter(trace* spCtx);
69 static const char* cpHtmlState(trace* spTrace, aint uiState, aint uiPhraseLength);
70 static const char* cpHtmlOpcode(trace* spCtx, const opcode* spOp, aint uiIndent);
71 static const char* cpHtmlPhrase(trace* spCtx, aint uiState, aint uiOffset, aint uiPhraseLength);
72 static void vHtmlPhraseUnicode(html_info* spInfo);
73 
77 typedef struct {
78  const achar* acpStr;
80  char* cpBuf;
81  int n;
82 } display_info;
83 static const char* s_cpLineEnd = "$";
84 static const char* s_cpLineTruncated = "...";
85 static const char* s_cpEmpty = "(empty)";
86 static void vAsciiHeader(trace* spCtx);
87 static void vAsciiSeparator(trace* spCtx, aint uiLastIndex);
88 static void vAsciiRecord(trace* spCtx, trace_record* spRec);
89 static void vAsciiFooter(trace* spCtx);
90 static const char* cpAsciiState(aint uiState, aint uiPhraseLength);
91 static const char* cpAsciiOpcode(trace* spCtx, const opcode* spOp, aint uiIndent);
92 static const char* cpAsciiPhrase(trace* spCtx, aint uiState, aint uiOffset, aint uiPhraseLength);
93 static abool bAsciiStringAscii(display_info* spInfo);
94 
98 void vDisplayHeader(trace* spCtx){
99  if(spCtx->sConfig.uiOutputType == TRACE_HTML){
100  vHtmlHeader(spCtx);
101  }else if(spCtx->sConfig.uiOutputType == TRACE_ASCII){
102  vAsciiHeader(spCtx);
103  }
104  // no header for APGEX
105 }
106 
110 void vDisplayRecord(trace* spCtx, trace_record* spRec, abool bIsMatchedPppt){
111  if(spCtx->sConfig.uiOutputType == TRACE_HTML){
112  if(spCtx->sConfig.bPppt && bIsMatchedPppt){
113  vHtmlPpptRecord(spCtx, spRec);
114  }else{
115  vHtmlRecord(spCtx, spRec);
116  }
117  }else if(spCtx->sConfig.uiOutputType == TRACE_ASCII){
118  if(spCtx->sConfig.bPppt && bIsMatchedPppt){
119  vAsciiPpptRecord(spCtx, spRec);
120  }else{
121  vAsciiRecord(spCtx, spRec);
122  }
123  }
124 }
125 
129 void vDisplaySeparator(trace* spCtx, aint uiLastIndex){
130  if(spCtx->sConfig.uiOutputType == TRACE_HTML){
131  vHtmlSeparator(spCtx, uiLastIndex);
132  }else if(spCtx->sConfig.uiOutputType == TRACE_ASCII){
133  vAsciiSeparator(spCtx, uiLastIndex);
134  }
135  // no header for APGEX
136 }
137 
141 void vDisplayFooter(trace* spCtx){
142  if(spCtx->sConfig.uiOutputType == TRACE_HTML){
143  vHtmlFooter(spCtx);
144  }else if(spCtx->sConfig.uiOutputType == TRACE_ASCII){
145  vAsciiFooter(spCtx);
146  }
147  // no footer for APGEX
148 }
149 
150 static aint uiAcharToHex(achar acChar, char* cpHex){
151  aint uiReturn = 0;
152  while(APG_TRUE){
153  if(acChar <= 0xFF){
154  uiReturn = (aint)sprintf(cpHex, "x%02"PRIXMAX"", (luint) acChar);
155  break;
156  }
157  if(acChar <= 0xFFFF){
158  uiReturn = (aint)sprintf(cpHex, "x%04"PRIXMAX"", (luint) acChar);
159  break;
160  }
161  if(acChar <= 0xFFFFFF){
162  uiReturn = (aint)sprintf(cpHex, "x%06"PRIXMAX"", (luint) acChar);
163  break;
164  }
165  if(acChar <= 0xFFFFFFFF){
166  uiReturn = (aint)sprintf(cpHex, "x%08"PRIXMAX"", (luint) acChar);
167  break;
168  }
169  if(acChar <= 0xFFFFFFFFFF){
170  uiReturn = (aint)sprintf(cpHex, "x%010"PRIXMAX"", (luint) acChar);
171  break;
172  }
173  if(acChar <= 0xFFFFFFFFFFFF){
174  uiReturn = (aint)sprintf(cpHex, "x%012"PRIXMAX"", (luint) acChar);
175  break;
176  }
177  if(acChar <= 0xFFFFFFFFFFFFFF){
178  uiReturn = (aint)sprintf(cpHex, "x%014"PRIXMAX"", (luint) acChar);
179  break;
180  }
181  uiReturn = (aint)sprintf(cpHex, "x%016"PRIXMAX"", (luint) acChar);
182  break;
183  }
184  return uiReturn;
185 }
186 
187 // ASCII FORMAT
188 static void vAsciiHeader(trace* spCtx){
189  fprintf(spCtx->spOut, "%4s|%3s|%3s|%1s|%3s|%3s|operator matched phrase or remaining unmatched string\n", "a", "b", "c", "d", "e", "f");
190 }
191 
192 static void vAsciiSeparator(trace* spCtx, aint uiLastIndex){
193  fprintf(spCtx->spOut, "Last Index: %"PRIuMAX"\n", (luint)uiLastIndex);
194 }
195 
196 static void vAsciiPpptRecord(trace* spCtx, trace_record* spRec){
197  fprintf(spCtx->spOut, "%4"PRIuMAX"|", (luint) spRec->uiThisRecord); // uiThisRecord
198  fprintf(spCtx->spOut, "%3"PRIuMAX"|", (luint) spRec->uiTreeDepth); // c
199  fprintf(spCtx->spOut, "%3d|", spRec->iTraceDepth); // d
200  switch(spRec->uiState){
201  case ID_MATCH:
202  fprintf(spCtx->spOut, "%1s|", "M"); // g
203  break;
204  case ID_NOMATCH:
205  fprintf(spCtx->spOut, "%1s|", "N"); // g
206  break;
207  case ID_EMPTY:
208  fprintf(spCtx->spOut, "%1s|", "E"); // g
209  break;
210  default:
211  fprintf(spCtx->spOut, "%1s|", "-"); // g
212  break;
213  }
214  fprintf(spCtx->spOut, "%3"PRIuMAX"|", (luint) spRec->uiOffset); // e
215  fprintf(spCtx->spOut, "%3"PRIuMAX"|", (luint) spRec->uiPhraseLength); // f
216  aint ui;
217  for(ui = 0; ui < spRec->uiTreeDepth; ui++){
218  fprintf(spCtx->spOut, "."); // indent
219  }
220  fprintf(spCtx->spOut, "PPPT<%s> ", cpAsciiOpcode(spCtx, spRec->spOpcode, 0));
221  fprintf(spCtx->spOut, "%s",
222  cpAsciiPhrase(spCtx, spRec->uiState, spRec->uiOffset, spRec->uiPhraseLength)); // phrase
223 }
224 static void vAsciiRecord(trace* spCtx, trace_record* spRec){
225  fprintf(spCtx->spOut, "%4"PRIuMAX"|", (luint) spRec->uiThisRecord); // a
226  fprintf(spCtx->spOut, "%3"PRIuMAX"|", (luint) spRec->uiTreeDepth); // c
227  fprintf(spCtx->spOut, "%3d|", spRec->iTraceDepth); // d
228  fprintf(spCtx->spOut, "%1s|", cpAsciiState(spRec->uiState, spRec->uiPhraseLength)); // g
229  fprintf(spCtx->spOut, "%3"PRIuMAX"|", (luint) spRec->uiOffset); // e
230  fprintf(spCtx->spOut, "%3"PRIuMAX"|", (luint) spRec->uiPhraseLength); // f
231  fprintf(spCtx->spOut, "%s ", cpAsciiOpcode(spCtx, spRec->spOpcode, spRec->uiTreeDepth)); // operator
232  fprintf(spCtx->spOut, "%s",
233  cpAsciiPhrase(spCtx, spRec->uiState, spRec->uiOffset, spRec->uiPhraseLength)); // phrase
234 }
235 static void vAsciiFooter(trace* spCtx){
236  fprintf(spCtx->spOut, "\n");
237  fprintf(spCtx->spOut, "legend:\n");
238  fprintf(spCtx->spOut, "a - line number\n");
239  fprintf(spCtx->spOut, "b - tree depth\n");
240  fprintf(spCtx->spOut, "c - trace depth\n");
241  fprintf(spCtx->spOut, "d - operator state (*)\n");
242  fprintf(spCtx->spOut, "e - phrase offset\n");
243  fprintf(spCtx->spOut, "f - phrase length\n");
244  fprintf(spCtx->spOut, "operator mnemonic - (**)\n");
245  fprintf(spCtx->spOut, "matched phrase, if state is M\n");
246  fprintf(spCtx->spOut, "(empty), if state is E\n");
247  fprintf(spCtx->spOut, "remaining unmatched input string, if state is N or -\n");
248  fprintf(spCtx->spOut, "%s - indicates that the input string display has been truncated\n", s_cpLineTruncated);
249  fprintf(spCtx->spOut, "%s - indicates the end of string\n", s_cpLineEnd);
250  fprintf(spCtx->spOut, " Beware of possible confusion if \"%s\" or \"%s\" exists in input string.\n",
251  s_cpLineTruncated, s_cpLineEnd);
252  fprintf(spCtx->spOut, "\n");
253  fprintf(spCtx->spOut, "(*) OPERATOR STATE:\n");
254  fprintf(spCtx->spOut, " - phrase opened\n");
255  fprintf(spCtx->spOut, " M phrase matched\n");
256  fprintf(spCtx->spOut, " E phrase empty (matched with length 0)\n");
257  fprintf(spCtx->spOut, " N phrase not matched\n");
258  fprintf(spCtx->spOut, "\n");
259  fprintf(spCtx->spOut, "(**) OPERATOR MNEMONICS:\n");
260  fprintf(spCtx->spOut, " original ABNF operators:\n");
261  fprintf(spCtx->spOut, "ALT - alternation\n");
262  fprintf(spCtx->spOut, "CAT - concatenation\n");
263  fprintf(spCtx->spOut, "REP - repetition\n");
264  fprintf(spCtx->spOut, "RNM - rule name\n");
265  fprintf(spCtx->spOut, "TRG - terminal range\n");
266  fprintf(spCtx->spOut, "TLS - terminal literal string (case insensitive)\n");
267  fprintf(spCtx->spOut, "TBS - terminal binary string (case sensitive)\n");
268  fprintf(spCtx->spOut, "\n");
269  fprintf(spCtx->spOut, " SABNF super set operators:\n");
270  fprintf(spCtx->spOut, "UDT - user-defined terminal\n");
271  fprintf(spCtx->spOut, "AND - positive look ahead\n");
272  fprintf(spCtx->spOut, "NOT - negative look ahead\n");
273  fprintf(spCtx->spOut, "BKA - positive look behind\n");
274  fprintf(spCtx->spOut, "BKN - negative look behind\n");
275  fprintf(spCtx->spOut, "BKR - back reference\n");
276  fprintf(spCtx->spOut, "ABG - anchor - begin of input string\n");
277  fprintf(spCtx->spOut, "AEN - anchor - end of input string\n");
278 }
279 static const char* cpAsciiState(aint uiState, aint uiPhraseLength) {
280  static const char* cpActive = "-";
281  static const char* cpMatch = "M";
282  static const char* cpNomatch = "N";
283  static const char* cpEmpty = "E";
284  static const char* cpUnknown = "U";
285  if (uiState == ID_ACTIVE) {
286  return cpActive;
287  }
288  if (uiState == ID_NOMATCH) {
289  return cpNomatch;
290  }
291  if (uiState == ID_MATCH) {
292  if (uiPhraseLength == 0) {
293  return cpEmpty;
294  }
295  return cpMatch;
296  }
297  return cpUnknown;
298 }
299 static const char* cpAsciiOpcode(trace* spCtx, const opcode* spOp, aint uiIndent) {
300  char* cpBuf = spCtx->cpBuf;
301  char* cpOp;
302  int n = 0;
303  aint ui;
304  for (ui = 0; ui < (int) uiIndent; ui += 1) {
305  n += sprintf(&cpBuf[n], ".");
306  }
307  switch (spOp->sGen.uiId) {
308  case ID_ALT:
309  cpOp = "ALT";
310  sprintf(&cpBuf[n], "%s(%"PRIuMAX")", cpOp, (luint) spOp->sAlt.uiChildCount);
311  break;
312  case ID_CAT:
313  cpOp = "CAT";
314  sprintf(&cpBuf[n], "%s(%"PRIuMAX")", cpOp, (luint) spOp->sCat.uiChildCount);
315  break;
316  case ID_REP:
317  cpOp = "REP";
318  if (spOp->sRep.uiMax == APG_INFINITE) {
319  sprintf(&cpBuf[n], "%s(%"PRIuMAX"*inf)", cpOp, (luint) spOp->sRep.uiMin);
320  } else {
321  sprintf(&cpBuf[n], "%s(%"PRIuMAX"*%"PRIuMAX")", cpOp, (luint) spOp->sRep.uiMin, (luint) spOp->sRep.uiMax);
322  }
323  break;
324  case ID_RNM:
325  cpOp = "RNM";
326  sprintf(&cpBuf[n], "%s(%s)", cpOp, spOp->sRnm.spRule->cpRuleName);
327  break;
328  case ID_TRG:
329  cpOp = "TRG";
330  sprintf(&cpBuf[n], "%s[x%"PRIXMAX"-%"PRIXMAX"]", cpOp, (luint) spOp->sTrg.acMin, (luint) spOp->sTrg.acMax);
331  break;
332  case ID_TBS:
333  cpOp = "TBS";
334  n += sprintf(&cpBuf[n], "%s[", cpOp);
335  if (spOp->sTbs.uiStrLen > 3) {
336  for (ui = 0; ui < 3; ui += 1) {
337  if (ui > 0) {
338  n += sprintf(&cpBuf[n], ", ");
339  }
340  n += sprintf(&cpBuf[n], "x%"PRIXMAX"", (luint) spOp->sTbs.acpStrTbl[ui]);
341  }
342  n += sprintf(&cpBuf[n], ", ...");
343  } else {
344  for (ui = 0; ui < spOp->sTbs.uiStrLen; ui += 1) {
345  if (ui > 0) {
346  n += sprintf(&cpBuf[n], ", ");
347  }
348  n += sprintf(&cpBuf[n], "x%"PRIXMAX"", (luint) spOp->sTbs.acpStrTbl[ui]);
349  }
350  }
351  sprintf(&cpBuf[n], "]");
352  break;
353  case ID_TLS:
354  cpOp = "TLS";
355  n += sprintf(&cpBuf[n], "%s(", cpOp);
356  if (spOp->sTls.uiStrLen > 3) {
357  for (ui = 0; ui < 3; ui += 1) {
358  cpBuf[n++]= (char) spOp->sTls.acpStrTbl[ui];
359  }
360  n += sprintf(&cpBuf[n], ", ...");
361  } else {
362  for (ui = 0; ui < spOp->sTls.uiStrLen; ui += 1) {
363  cpBuf[n++]= (char) spOp->sTls.acpStrTbl[ui];
364  }
365  }
366  sprintf(&cpBuf[n], ")");
367  break;
368  case ID_UDT:
369  cpOp = "UDT";
370  sprintf(&cpBuf[n], "%s(%s)", cpOp, spOp->sUdt.spUdt->cpUdtName);
371  break;
372  case ID_AND:
373  cpOp = "AND";
374  sprintf(&cpBuf[n], "%s", cpOp);
375  break;
376  case ID_NOT:
377  cpOp = "NOT";
378  sprintf(&cpBuf[n], "%s", cpOp);
379  break;
380  case ID_BKR:
381  cpOp = "BKR";
382  sprintf(&cpBuf[n], "%s", cpOp);
383  break;
384  case ID_BKA:
385  cpOp = "BKA";
386  sprintf(&cpBuf[n], "%s", cpOp);
387  break;
388  case ID_BKN:
389  cpOp = "BKN";
390  sprintf(&cpBuf[n], "%s", cpOp);
391  break;
392  case ID_ABG:
393  cpOp = "ABG";
394  sprintf(&cpBuf[n], "%s", cpOp);
395  break;
396  case ID_AEN:
397  cpOp = "AEN";
398  sprintf(&cpBuf[n], "%s", cpOp);
399  break;
400  default:
401  cpOp = "UNK";
402  sprintf(&cpBuf[n], "%s", cpOp);
403  break;
404  }
405  return cpBuf;
406 }
407 static abool bAsciiStringAscii(display_info* spInfo){
408  abool bReturn = APG_FAILURE;
409  aint ui;
410  for(ui = 0; ui < spInfo->uiStrLen; ui++){
411  achar acChar = spInfo->acpStr[ui];
412  if (acChar >= 32 && acChar <= 126){
413  spInfo->cpBuf[spInfo->n++] = (char)acChar;
414  }else if(acChar == 9){
415  spInfo->n += sprintf(&spInfo->cpBuf[spInfo->n], "\\t");
416  }else if(acChar == 10){
417  spInfo->n += sprintf(&spInfo->cpBuf[spInfo->n], "\\n");
418  }else if(acChar == 13){
419  spInfo->n += sprintf(&spInfo->cpBuf[spInfo->n], "\\r");
420  }else{
421  spInfo->n += uiAcharToHex(acChar, &spInfo->cpBuf[spInfo->n]);
422  }
423  if(spInfo->n >= s_uiMaxPhraseLength){
424  goto truncate;
425  }
426  }
427  bReturn = APG_SUCCESS;
428  truncate:;
429  return bReturn;
430 }
431 static const char* cpAsciiPhrase(trace* spCtx, aint uiState, aint uiOffset, aint uiPhraseLength){
432  display_info sInfo;
433  sInfo.acpStr = spCtx->spParserCtx->acpInputString + uiOffset;
434  sInfo.uiStrLen = spCtx->spParserCtx->uiInputStringLength - uiOffset;
435  sInfo.cpBuf = spCtx->cpBuf;
436  sInfo.n = 0;
437  if((uiState == ID_ACTIVE) || (uiState == ID_NOMATCH)){
438  if(bAsciiStringAscii(&sInfo)){
439  sInfo.n += sprintf(&sInfo.cpBuf[sInfo.n], "%s", s_cpLineEnd);
440  }else{
441  sInfo.n += sprintf(&sInfo.cpBuf[sInfo.n], "%s", s_cpLineTruncated);
442  }
443  }else{
444  if(uiPhraseLength){
445  sInfo.uiStrLen = uiPhraseLength;
446  bAsciiStringAscii(&sInfo);
447  }else{
448  sInfo.n += sprintf(&sInfo.cpBuf[sInfo.n], "%s", s_cpEmpty);
449  }
450  }
451  sInfo.cpBuf[sInfo.n++] = 10;
452  sInfo.cpBuf[sInfo.n] = 0;
453  return spCtx->cpBuf;
454 }
455 
456 // HTML FORMAT
457 static void vHtmlHeader(trace* spCtx){
458  // output the page header
459  fprintf(spCtx->spOut, "%s", s_cpHtmlHeader);
460 
461  // open the table
462  fprintf(spCtx->spOut, "%s", "<table class=\"apg-trace\">\n");
463  fprintf(spCtx->spOut,
464  "<tr><th>(a)</th><th>(b)</th><th>(c)</th><th>(d)</th><th>(e)</th><th>(f)</th><th>operator</th><th>phrase</th></tr>\n");
465 }
466 static void vHtmlSeparator(trace* spCtx, aint uiLastIndex){
467  fprintf(spCtx->spOut,
468  "<tr><td colspan=\"9\">Last Index: %"PRIuMAX"</td></tr>\n", (luint)uiLastIndex);
469 }
470 static void vHtmlPpptRecord(trace* spCtx, trace_record* spRec){
471  fprintf(spCtx->spOut, "%s", "<tr>");
472  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiThisRecord); // a
473  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiTreeDepth); // c
474  fprintf(spCtx->spOut, "<td>%d</td>", spRec->iTraceDepth); // d
475  fprintf(spCtx->spOut, "<td>%s</td>", cpHtmlState(spCtx, spRec->uiState, spRec->uiPhraseLength)); // g
476  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiOffset); // e
477  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiPhraseLength); // f
478  aint ui = 0;
479  fprintf(spCtx->spOut, "<td>");
480  for(; ui < spRec->uiTreeDepth; ui++){
481  fprintf(spCtx->spOut, ".");
482  }
483  fprintf(spCtx->spOut, "PPPT&lt;%s&gt;</td>", cpHtmlOpcode(spCtx, spRec->spOpcode, 0)); // operator
484  fprintf(spCtx->spOut, "<td>%s</td>",
485  cpHtmlPhrase(spCtx, spRec->uiState, spRec->uiOffset, spRec->uiPhraseLength)); // phrase
486  fprintf(spCtx->spOut, "%s", "</tr>\n");
487 }
488 static void vHtmlRecord(trace* spCtx, trace_record* spRec){
489  fprintf(spCtx->spOut, "%s", "<tr>");
490  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiThisRecord); // a
491  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiTreeDepth); // c
492  fprintf(spCtx->spOut, "<td>%d</td>", spRec->iTraceDepth); // d
493  fprintf(spCtx->spOut, "<td>%s</td>", cpHtmlState(spCtx, spRec->uiState, spRec->uiPhraseLength)); // g
494  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiOffset); // e
495  fprintf(spCtx->spOut, "<td>%"PRIuMAX"</td>", (luint) spRec->uiPhraseLength); // f
496  fprintf(spCtx->spOut, "<td>%s</td>", cpHtmlOpcode(spCtx, spRec->spOpcode, spRec->uiTreeDepth)); // operator
497  fprintf(spCtx->spOut, "<td>%s</td>",
498  cpHtmlPhrase(spCtx, spRec->uiState, spRec->uiOffset, spRec->uiPhraseLength)); // phrase
499  fprintf(spCtx->spOut, "%s", "</tr>\n");
500 }
501 static void vHtmlFooter(trace* spCtx){
502  // close the table
503  fprintf(spCtx->spOut, "%s", "</table>\n");
504 
505  // output the page footer
506  fprintf(spCtx->spOut, "%s", s_cpHtmlFooter);
507 }
508 
509 static const char* cpHtmlState(trace* spTrace, aint uiState, aint uiPhraseLength) {
510  if (uiState == ID_ACTIVE) {
511  return "<span class=\"apg-active\">&darr;&nbsp;</span>";
512  }
513  if (uiState == ID_NOMATCH) {
514  return "<span class=\"apg-nomatch\">&uarr;N</span>";
515  }
516  if (uiState == ID_MATCH) {
517  if (uiPhraseLength == 0) {
518  return "<span class=\"apg-empty\">&uarr;E</span>";
519  }
520  aint* uipLookaround = (aint*)vpVecLast(spTrace->vpLookaroundStack);
521  if(uipLookaround){
522  if(*uipLookaround == ID_LOOKAROUND_AHEAD){
523  return "<span class=\"apg-lh-match\">&uarr;M</span>";
524  }
525  return "<span class=\"apg-lb-match\">&uarr;M</span>";
526  }
527  return "<span class=\"apg-match\">&uarr;M</span>";
528  }
529  return "<span class=\"apg-nomatch\">&#10008;</span>";
530 }
531 static const char* cpHtmlOpcode(trace* spCtx, const opcode* spOp, aint uiIndent) {
532  char* cpBuf = spCtx->cpBuf;
533  char* cpOp;
534  int n = 0;
535  aint ui;
536  for (ui = 0; ui < (int) uiIndent; ui += 1) {
537  n += sprintf(&cpBuf[n], ".");
538  }
539  switch (spOp->sGen.uiId) {
540  case ID_ALT:
541  cpOp = "ALT";
542  sprintf(&cpBuf[n], "%s(%"PRIuMAX")", cpOp, (luint) spOp->sAlt.uiChildCount);
543  break;
544  case ID_CAT:
545  cpOp = "CAT";
546  sprintf(&cpBuf[n], "%s(%"PRIuMAX")", cpOp, (luint) spOp->sCat.uiChildCount);
547  break;
548  case ID_REP:
549  cpOp = "REP";
550  if (spOp->sRep.uiMax == APG_INFINITE) {
551  sprintf(&cpBuf[n], "%s(%"PRIuMAX"*&infin;)", cpOp, (luint) spOp->sRep.uiMin);
552  } else {
553  sprintf(&cpBuf[n], "%s(%"PRIuMAX"*%"PRIuMAX")", cpOp, (luint) spOp->sRep.uiMin, (luint) spOp->sRep.uiMax);
554  }
555  break;
556  case ID_RNM:
557  cpOp = "RNM";
558  sprintf(&cpBuf[n], "%s(%s)", cpOp, spOp->sRnm.spRule->cpRuleName);
559  break;
560  case ID_TRG:
561  cpOp = "TRG";
562  sprintf(&cpBuf[n], "%s[x%"PRIXMAX"-%"PRIXMAX"]", cpOp, (luint) spOp->sTrg.acMin, (luint) spOp->sTrg.acMax);
563  break;
564  case ID_TBS:
565  cpOp = "TBS";
566  n += sprintf(&cpBuf[n], "%s[", cpOp);
567  if (spOp->sTbs.uiStrLen > 3) {
568  for (ui = 0; ui < 3; ui += 1) {
569  if (ui > 0) {
570  n += sprintf(&cpBuf[n], ", ");
571  }
572  n += sprintf(&cpBuf[n], "x%"PRIXMAX"", (luint) spOp->sTbs.acpStrTbl[ui]);
573  }
574  n += sprintf(&cpBuf[n], ", ...");
575  } else {
576  for (ui = 0; ui < spOp->sTbs.uiStrLen; ui += 1) {
577  if (ui > 0) {
578  n += sprintf(&cpBuf[n], ", ");
579  }
580  n += sprintf(&cpBuf[n], "x%"PRIXMAX"", (luint) spOp->sTbs.acpStrTbl[ui]);
581  }
582  }
583  sprintf(&cpBuf[n], "]");
584  break;
585  case ID_TLS:
586  cpOp = "TLS";
587  n += sprintf(&cpBuf[n], "%s(", cpOp);
588  if (spOp->sTls.uiStrLen > 3) {
589  for (ui = 0; ui < 3; ui += 1) {
590  n += sprintf(&cpBuf[n], "&#%"PRIuMAX";", (luint) spOp->sTls.acpStrTbl[ui]);
591  }
592  n += sprintf(&cpBuf[n], ", ...");
593  } else {
594  for (ui = 0; ui < spOp->sTls.uiStrLen; ui += 1) {
595  n += sprintf(&cpBuf[n], "&#%"PRIuMAX";", (luint) spOp->sTls.acpStrTbl[ui]);
596  }
597  }
598  sprintf(&cpBuf[n], ")");
599  break;
600  case ID_UDT:
601  cpOp = "UDT";
602  sprintf(&cpBuf[n], "%s(%s)", cpOp, spOp->sUdt.spUdt->cpUdtName);
603  break;
604  case ID_AND:
605  cpOp = "AND";
606  sprintf(&cpBuf[n], "%s", cpOp);
607  break;
608  case ID_NOT:
609  cpOp = "NOT";
610  sprintf(&cpBuf[n], "%s", cpOp);
611  break;
612  case ID_BKR:
613  cpOp = "BKR";
614  sprintf(&cpBuf[n], "%s", cpOp);
615  break;
616  case ID_BKA:
617  cpOp = "BKA";
618  sprintf(&cpBuf[n], "%s", cpOp);
619  break;
620  case ID_BKN:
621  cpOp = "BKN";
622  sprintf(&cpBuf[n], "%s", cpOp);
623  break;
624  case ID_ABG:
625  cpOp = "ABG";
626  sprintf(&cpBuf[n], "%s", cpOp);
627  break;
628  case ID_AEN:
629  cpOp = "AEN";
630  sprintf(&cpBuf[n], "%s", cpOp);
631  break;
632  default:
633  cpOp = "UNK";
634  sprintf(&cpBuf[n], "%s", cpOp);
635  break;
636  }
637  return cpBuf;
638 }
645 static void vHtmlPhraseUnicode(html_info* spInfo){
646  const achar* acpOut = spInfo->acpInput;
647  char* cpBuf = spInfo->cpOutput;
648  const char* cpControl;
649  int n = 0;
650  aint ui;
651  n += sprintf(&cpBuf[n], "%s", spInfo->cpEmpty);
652  if (spInfo->uiMatched > 0) {
653  aint* uipLookaround = (aint*)vpVecLast(spInfo->spTrace->vpLookaroundStack);
654  if(uipLookaround){
655  if(*uipLookaround == ID_LOOKAROUND_AHEAD){
656  n += sprintf(&cpBuf[n], "<span class=\"apg-lh-match\">");
657  }else{
658  n += sprintf(&cpBuf[n], "<span class=\"apg-lb-match\">");
659  }
660 
661  }else{
662  n += sprintf(&cpBuf[n], "<span class=\"apg-match\">");
663  }
664  for (ui = 0; ui < spInfo->uiMatched; ui++, acpOut++) {
665  cpControl = cpIsControl(*acpOut);
666  if(cpControl){
667  n += sprintf(&cpBuf[n], "<span class=\"apg-ctrl-char\">%s</span>", cpControl);
668  }else if(*acpOut == 32){
669  n += sprintf(&cpBuf[n], "&nbsp;");
670  }else if(bIsUnicode(*acpOut)){
671  n += sprintf(&cpBuf[n], "&#%"PRIuMAX";", (luint) *acpOut);
672  }else{
673  n += (int)uiAcharToHex(*acpOut, &cpBuf[n]);
674  }
675  }
676  n += sprintf(&cpBuf[n], "</span>");
677  }
678  if (spInfo->uiRemainder > 0) {
679  n += sprintf(&cpBuf[n], "<span class=\"apg-remainder\">");
680  for (ui = 0; ui < spInfo->uiRemainder; ui++, acpOut++) {
681  cpControl = cpIsControl(*acpOut);
682  if(cpControl){
683  n += sprintf(&cpBuf[n], "<span class=\"apg-ctrl-char\">%s</span>", cpControl);
684  }else if(*acpOut == 32){
685  n += sprintf(&cpBuf[n], "&nbsp;");
686  }else if(bIsUnicode(*acpOut)){
687  n += sprintf(&cpBuf[n], "&#%"PRIuMAX";", (luint) *acpOut);
688  }else{
689  n += (int)uiAcharToHex(*acpOut, &cpBuf[n]);
690  }
691  }
692  n += sprintf(&cpBuf[n], "</span>");
693  }
694  n += sprintf(&cpBuf[n], "%s", spInfo->cpLastChar);
695 }
696 static const char* cpHtmlPhrase(trace* spCtx, aint uiState, aint uiOffset, aint uiPhraseLength) {
697  aint uiMatchedLen, uiRemainder, uiLeft;
698  html_info sInfo;
699  char *cpEmpty, *cpLastChar;
700  if (uiState == ID_MATCH && uiPhraseLength == 0) {
701  cpEmpty = "<span class=\"apg-empty\">&#120576</span>";
702  } else {
703  cpEmpty = "";
704  }
705  uiLeft = spCtx->spParserCtx->uiSubStringEnd - uiOffset;
706  cpLastChar = "<span class=\"apg-line-end\">&bull;</span>";
707  if (uiLeft >= s_uiMaxPhraseLength) {
708  uiLeft = s_uiMaxPhraseLength;
709  cpLastChar = "<span class=\"apg-line-end\">&hellip;</span>";
710  }
711  uiMatchedLen = 0;
712  if (uiState == ID_MATCH) {
713  uiMatchedLen = uiPhraseLength < uiLeft ? uiPhraseLength : uiLeft;
714  }
715  uiLeft -= uiMatchedLen;
716  uiRemainder = s_uiMaxPhraseLength - uiMatchedLen;
717  if(uiLeft < uiRemainder){
718  uiRemainder = uiLeft;
719  }
720 
721  sInfo.spTrace = spCtx;
722  sInfo.acpInput = &spCtx->spParserCtx->acpInputString[uiOffset];
723  sInfo.cpEmpty = cpEmpty;
724  sInfo.cpLastChar = cpLastChar;
725  sInfo.cpOutput = spCtx->cpBuf;
726  sInfo.uiMatched = uiMatchedLen;
727  sInfo.uiRemainder = uiRemainder;
728  vHtmlPhraseUnicode(&sInfo);
729  return sInfo.cpOutput;
730 }
731 
732 static const char* cpIsControl(achar acChar){
733  if(acChar >= 0 && acChar <=31){
734  return s_caControlChars[(luint)acChar];
735  }
736  if(acChar == 127){
737  return s_caControlChars[32];
738  }
739  return NULL;
740 }
741 static abool bIsUnicode(achar acChar){
742  if(acChar >= 33 && acChar <=126){
743  return APG_TRUE;
744  }
745  if(acChar >= 0x80 && acChar <=0xd7ff){
746  return APG_TRUE;
747  }
748  if(acChar >= 0xe000 && acChar <= 0xffff){
749  return APG_TRUE;
750  }
751  return APG_FALSE;
752 }
753 
754 static const char* s_cpHtmlHeader = "<!DOCTYPE html>\n"
755  "<html lang=\"en\">\n"
756  "<head>\n"
757  "<meta charset=\"utf-8\">\n"
758  "<title>trace</title>\n"
759  "<style>\n"
760  ".apg-mono {\n"
761  " font-family: monospace;\n"
762  "}\n"
763  ".apg-active {\n"
764  " font-weight: bold;\n"
765  " color: #000000;\n"
766  "}\n"
767  ".apg-match {\n"
768  " font-weight: bold;\n"
769  " background-color: #6680FF;\n"
770  " color: white;\n"
771  "}\n"
772  ".apg-empty {\n"
773  " font-weight: bold;\n"
774  " background-color: #0fbd0f;\n"
775  " color: white;\n"
776  "}\n"
777  ".apg-nomatch {\n"
778  " font-weight: bold;\n"
779  " background-color: #FF4000;\n"
780  " color: white;\n"
781  "}\n"
782  ".apg-lh-match {\n"
783  " font-weight: bold;\n"
784  " background-color: #D966FF;\n"
785  " color: white;\n"
786  "}\n"
787  ".apg-lb-match {\n"
788  " font-weight: bold;\n"
789  " background-color: #FF944D;\n"
790  " color: white;\n"
791  "}\n"
792  ".apg-remainder {\n"
793  " font-weight: bold;\n"
794  " color: gray;/* #999999 */\n"
795  "}\n"
796  ".apg-ctrl-char {\n"
797  " font-weight: bolder;\n"
798  " font-style: italic;\n"
799  " font-size: .8em;\n"
800  " color: black;\n"
801  "}\n"
802  ".apg-line-end {\n"
803  " font-weight: bold;\n"
804  " color: #000000;\n"
805  "}\n"
806  ".apg-error {\n"
807  " font-weight: bold;\n"
808  " color: #FF4000;\n"
809  "}\n"
810  ".apg-phrase {\n"
811  " color: #000000;\n"
812  " background-color: #8caae6;\n"
813  "}\n"
814  ".apg-empty-phrase {\n"
815  " color: #0fbd0f;\n"
816  "}\n"
817  "table.apg-state {\n"
818  " font-family: monospace;\n"
819  " margin-top: 5px;\n"
820  " font-size: 11px;\n"
821  " line-height: 130%;\n"
822  " text-align: left;\n"
823  " border: 1px solid black;\n"
824  " border-collapse: collapse;\n"
825  "}\n"
826  "table.apg-state th,\n"
827  "table.apg-state td {\n"
828  " text-align: left;\n"
829  " border: 1px solid black;\n"
830  " border-collapse: collapse;\n"
831  "}\n"
832  "table.apg-state th:nth-last-child(2),\n"
833  "table.apg-state td:nth-last-child(2) {\n"
834  " text-align: right;\n"
835  "}\n"
836  "table.apg-state caption {\n"
837  " font-size: 125%;\n"
838  " line-height: 130%;\n"
839  " font-weight: bold;\n"
840  " text-align: left;\n"
841  "}\n"
842  "table.apg-stats {\n"
843  " font-family: monospace;\n"
844  " margin-top: 5px;\n"
845  " font-size: 11px;\n"
846  " line-height: 130%;\n"
847  " text-align: right;\n"
848  " border: 1px solid black;\n"
849  " border-collapse: collapse;\n"
850  "}\n"
851  "table.apg-stats th,\n"
852  "table.apg-stats td {\n"
853  " text-align: right;\n"
854  " border: 1px solid black;\n"
855  " border-collapse: collapse;\n"
856  "}\n"
857  "table.apg-stats caption {\n"
858  " font-size: 125%;\n"
859  " line-height: 130%;\n"
860  " font-weight: bold;\n"
861  " text-align: left;\n"
862  "}\n"
863  "table.apg-trace {\n"
864  " font-family: monospace;\n"
865  " margin-top: 5px;\n"
866  " font-size: 11px;\n"
867  " line-height: 130%;\n"
868  " text-align: right;\n"
869  " border: 1px solid black;\n"
870  " border-collapse: collapse;\n"
871  "}\n"
872  "table.apg-trace caption {\n"
873  " font-size: 125%;\n"
874  " line-height: 130%;\n"
875  " font-weight: bold;\n"
876  " text-align: left;\n"
877  "}\n"
878  "table.apg-trace th,\n"
879  "table.apg-trace td {\n"
880  " text-align: right;\n"
881  " border: 1px solid black;\n"
882  " border-collapse: collapse;\n"
883  "}\n"
884  "table.apg-trace th:last-child,\n"
885  "table.apg-trace th:nth-last-child(2),\n"
886  "table.apg-trace td:last-child,\n"
887  "table.apg-trace td:nth-last-child(2) {\n"
888  " text-align: left;\n"
889  "}\n"
890  "table.apg-grammar {\n"
891  " font-family: monospace;\n"
892  " margin-top: 5px;\n"
893  " font-size: 11px;\n"
894  " line-height: 130%;\n"
895  " text-align: right;\n"
896  " border: 1px solid black;\n"
897  " border-collapse: collapse;\n"
898  "}\n"
899  "table.apg-grammar caption {\n"
900  " font-size: 125%;\n"
901  " line-height: 130%;\n"
902  " font-weight: bold;\n"
903  " text-align: left;\n"
904  "}\n"
905  "table.apg-grammar th,\n"
906  "table.apg-grammar td {\n"
907  " text-align: right;\n"
908  " border: 1px solid black;\n"
909  " border-collapse: collapse;\n"
910  "}\n"
911  "table.apg-grammar th:last-child,\n"
912  "table.apg-grammar td:last-child {\n"
913  " text-align: left;\n"
914  "}\n"
915  "table.apg-rules {\n"
916  " font-family: monospace;\n"
917  " margin-top: 5px;\n"
918  " font-size: 11px;\n"
919  " line-height: 130%;\n"
920  " text-align: right;\n"
921  " border: 1px solid black;\n"
922  " border-collapse: collapse;\n"
923  "}\n"
924  "table.apg-rules caption {\n"
925  " font-size: 125%;\n"
926  " line-height: 130%;\n"
927  " font-weight: bold;\n"
928  " text-align: left;\n"
929  "}\n"
930  "table.apg-rules th,\n"
931  "table.apg-rules td {\n"
932  " text-align: right;\n"
933  " border: 1px solid black;\n"
934  " border-collapse: collapse;\n"
935  "}\n"
936  "table.apg-rules a {\n"
937  " color: #003399 !important;\n"
938  "}\n"
939  "table.apg-rules a:hover {\n"
940  " color: #8caae6 !important;\n"
941  "}\n"
942  "table.apg-attrs {\n"
943  " font-family: monospace;\n"
944  " margin-top: 5px;\n"
945  " font-size: 11px;\n"
946  " line-height: 130%;\n"
947  " text-align: center;\n"
948  " border: 1px solid black;\n"
949  " border-collapse: collapse;\n"
950  "}\n"
951  "table.apg-attrs caption {\n"
952  " font-size: 125%;\n"
953  " line-height: 130%;\n"
954  " font-weight: bold;\n"
955  " text-align: left;\n"
956  "}\n"
957  "table.apg-attrs th,\n"
958  "table.apg-attrs td {\n"
959  " text-align: center;\n"
960  " border: 1px solid black;\n"
961  " border-collapse: collapse;\n"
962  "}\n"
963  "table.apg-attrs th:nth-child(1),\n"
964  "table.apg-attrs th:nth-child(2),\n"
965  "table.apg-attrs th:nth-child(3) {\n"
966  " text-align: right;\n"
967  "}\n"
968  "table.apg-attrs td:nth-child(1),\n"
969  "table.apg-attrs td:nth-child(2),\n"
970  "table.apg-attrs td:nth-child(3) {\n"
971  " text-align: right;\n"
972  "}\n"
973  "table.apg-attrs a {\n"
974  " color: #003399 !important;\n"
975  "}\n"
976  "table.apg-attrs a:hover {\n"
977  " color: #8caae6 !important;\n"
978  "}\n"
979  "</style>\n"
980  "</head>\n"
981  "<body>\n";
982 static const char* s_cpHtmlFooter =
983  "<p class=\"apg-mono\">legend:<br>\n"
984  "(a)&nbsp;-&nbsp;this line number<br>\n"
985  "(b)&nbsp;-&nbsp;tree depth<br>\n"
986  "(c)&nbsp;-&nbsp;trace depth<br>\n"
987  "(d)&nbsp;-&nbsp;operator state<br>\n"
988  "(e)&nbsp;-&nbsp;phrase offset<br>\n"
989  "(f)&nbsp;-&nbsp;phrase length<br>\n"
990  "&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-active\">&darr;</span>&nbsp;&nbsp;phrase opened<br>\n"
991  "&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-match\">&uarr;M</span> phrase matched<br>\n"
992  "&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-empty\">&uarr;E</span> phrase matched empty (phrase length = 0)<br>\n"
993  "&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-nomatch\">&uarr;N</span> phrase not matched<br>\n"
994  "operator&nbsp;-&nbsp;ALT, CAT, REP, RNM, TRG, TLS, TBS<sup>&dagger;</sup>, UDT, AND, NOT, BKA, BKN, BKR, ABG, AEN<sup>&Dagger;</sup><br>\n"
995  "phrase&nbsp;&nbsp;&nbsp;-&nbsp;up to 120 characters of the phrase being matched<br>\n"
996  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-match\">matched characters</span><br>\n"
997  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-lh-match\">matched characters in look ahead mode</span><br>\n"
998  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-lb-match\">matched characters in look behind mode</span><br>\n"
999  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-remainder\">remainder characters(not yet examined by parser)</span><br>\n"
1000  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-ctrl-char\">control characters, TAB, LF, CR, etc. (ASCII mode only)</span><br>\n"
1001  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-empty\">&#120634;</span> empty string<br>\n"
1002  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-line-end\">&bull;</span> end of input string<br>\n"
1003  "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;<span class=\"apg-line-end\">&hellip;</span> input string display truncated<br>\n"
1004  "</p>\n"
1005  "<p class=\"apg-mono\">\n"
1006  "<sup>&dagger;</sup>original ABNF operators:<br>\n"
1007  "ALT - alternation<br>\n"
1008  "CAT - concatenation<br>\n"
1009  "REP - repetition<br>\n"
1010  "RNM - rule name<br>\n"
1011  "TRG - terminal range<br>\n"
1012  "TLS - terminal literal string (case insensitive)<br>\n"
1013  "TBS - terminal binary string (case sensitive)<br>\n"
1014  "<br>\n"
1015  "<sup>&Dagger;</sup>super set SABNF operators:<br>\n"
1016  "UDT - user-defined terminal<br>\n"
1017  "AND - positive look ahead<br>\n"
1018  "NOT - negative look ahead<br>\n"
1019  "BKA - positive look behind<br>\n"
1020  "BKN - negative look behind<br>\n"
1021  "BKR - back reference<br>\n"
1022  "ABG - anchor - begin of input string<br>\n"
1023  "AEN - anchor - end of input string<br>\n"
1024  "</p>\n"
1025  "</body>\n"
1026  "</html>\n";
1027 
1028 #endif /* APG_TRACE */
lib.h
This header "#include"s all publid lib headers and other standard headers needed by most objects.
apg.h
The APG header file.
APG_INFINITE
#define APG_INFINITE
Definition: apg.h:320
vHtmlHeader
void vHtmlHeader(FILE *spFile, const char *cpTitle)
Prints an HTML header to an open file.
Definition: api.c:565
APG_FAILURE
#define APG_FAILURE
Definition: apg.h:308
trace::spParserCtx
parser * spParserCtx
Pointer back to the parent parser's context.
Definition: tracep.h:95
vDisplaySeparator
void vDisplaySeparator(trace *spCtx, aint uiLastIndex)
Display a separator between trace outputs (apgex only)
Definition: trace-out.c:129
ID_RNM
#define ID_RNM
rule name
Definition: parser.h:46
trace::spOut
FILE * spOut
Pointer to the open output file.
Definition: tracep.h:98
trace_record::uiThisRecord
aint uiThisRecord
The record index of the current record.
Definition: tracep.h:63
parserp.h
Private header for the SABNF parser.
trace::cpBuf
char * cpBuf
May be greater than zero if configured to not display the first N records.
Definition: tracep.h:108
vDisplayFooter
void vDisplayFooter(trace *spCtx)
Display the trace footer.
Definition: trace-out.c:141
html_info::acpInput
const achar * acpInput
Pointer to the input string.
Definition: trace-out.c:53
trace_record::uiPhraseLength
aint uiPhraseLength
The phrase length of a successful match.
Definition: tracep.h:65
trace_record::spOpcode
const opcode * spOpcode
Pointer to the opcode for the current node.
Definition: tracep.h:67
ID_ALT
#define ID_ALT
alternation
Definition: parser.h:43
ID_BKR
#define ID_BKR
back reference to a previously matched rule or UDT name
Definition: parser.h:58
ID_UDT
#define ID_UDT
user-defined terminal
Definition: parser.h:55
trace_config::bPppt
abool bPppt
However, no records are actually displayed.
Definition: tracep.h:85
achar
uint_fast8_t achar
achar is the type for the parser's alphabet characters.
Definition: apg.h:91
ID_EMPTY
#define ID_EMPTY
indicates a matched empty phrase parser state on return from parse tree below this node
Definition: parser.h:75
trace::vpLookaroundStack
void * vpLookaroundStack
Pointer to a stack require to keep track of when tracing in look around mode.
Definition: tracep.h:100
ID_NOT
#define ID_NOT
negative look ahead
Definition: parser.h:57
ID_AND
#define ID_AND
positive look ahead
Definition: parser.h:56
trace::sConfig
trace_config sConfig
Pointer to the trace configuration.
Definition: tracep.h:110
trace_record::uiState
aint uiState
The parser's state for this node (ID_ACTIVE, ID_MATCH, etc.)
Definition: tracep.h:66
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
vpVecLast
void * vpVecLast(void *vpCtx)
Get the last element one the vector. The vector is not altered.
Definition: vector.c:343
trace_config::uiOutputType
aint uiOutputType
Output type identifier (TRACE_ASCII or TRACE_HTML)
Definition: tracep.h:77
trace_record::iTraceDepth
int iTraceDepth
The partial parse tree depth (a subset possibly restricted by the configuration.)
Definition: tracep.h:62
ID_CAT
#define ID_CAT
concatenation
Definition: parser.h:44
display_info::cpBuf
char * cpBuf
Pointer to a scratch buffer.
Definition: trace-out.c:80
vHtmlFooter
void vHtmlFooter(FILE *spFile)
Prints an HTML footer to an open file.
Definition: api.c:589
trace_record::uiTreeDepth
aint uiTreeDepth
The actual parse tree depth.
Definition: tracep.h:61
display_info::acpStr
const achar * acpStr
Pointer to the matched phrase.
Definition: trace-out.c:78
ID_TRG
#define ID_TRG
terminal range
Definition: parser.h:47
ID_REP
#define ID_REP
repetition
Definition: parser.h:45
APG_SUCCESS
#define APG_SUCCESS
Definition: apg.h:307
ID_LOOKAROUND_AHEAD
#define ID_LOOKAROUND_AHEAD
the parser presently is in look ahead mode
Definition: parser.h:110
ID_ACTIVE
#define ID_ACTIVE
indicates active parser state, parser has just entered the node and is moving down the parse tree
Definition: parser.h:72
ID_MATCH
#define ID_MATCH
indicates a matched phrase parser state on return from parse tree below this node
Definition: parser.h:73
luint
uintmax_t luint
luint is used to cast integers suitable for the %"PRIuMAX" printf format.
Definition: apg.h:133
ID_BKA
#define ID_BKA
positive look behind
Definition: parser.h:59
html_info::cpEmpty
char * cpEmpty
The display for and empty match.
Definition: trace-out.c:57
html_info::uiRemainder
aint uiRemainder
Length of the remaining input string beyond the current sub-phrase.
Definition: trace-out.c:56
display_info::uiStrLen
aint uiStrLen
Length of the matched phrase.
Definition: trace-out.c:79
display_info::n
int n
Keeps track of the length of the string in the scratch buffer.
Definition: trace-out.c:81
tracep.h
Private header file for the trace functions.
ID_TLS
#define ID_TLS
terminal literal string
Definition: parser.h:49
APG_TRUE
#define APG_TRUE
Definition: apg.h:291
trace_record
The information recorded & displayed by the trace object for each node visited.
Definition: tracep.h:60
html_info::spTrace
trace * spTrace
Pointer to the trace object's context.
Definition: trace-out.c:52
display_info
Keeps track of the display state for ASCII display.
Definition: trace-out.c:77
TRACE_HTML
#define TRACE_HTML
Identifier for HTML trace record format.
Definition: trace.h:45
ID_BKN
#define ID_BKN
negative look behind
Definition: parser.h:60
abool
uint8_t abool
abool is the APG bool type.
Definition: apg.h:140
ID_NOMATCH
#define ID_NOMATCH
indicates that no phrase was matched on return from parse tree below this node
Definition: parser.h:74
html_info::cpLastChar
char * cpLastChar
The display symbol for the end of string character.
Definition: trace-out.c:58
html_info
Keeps track of the display state for HTML display.
Definition: trace-out.c:51
TRACE_ASCII
#define TRACE_ASCII
Identifier for plain ASCII trace record format.
Definition: trace.h:41
ID_ABG
#define ID_ABG
anchor - beginning of string
Definition: parser.h:61
vDisplayRecord
void vDisplayRecord(trace *spCtx, trace_record *spRec, abool bIsMatchedPppt)
Display one trace record.
Definition: trace-out.c:110
trace
The trace object context. Maintains the trace object's state.
Definition: tracep.h:91
ID_TBS
#define ID_TBS
terminal binary string
Definition: parser.h:48
trace_record::uiOffset
aint uiOffset
The offset into the input string for the first character of the sub-phrase being matched.
Definition: tracep.h:64
html_info::uiMatched
aint uiMatched
True if a phrase was matched.
Definition: trace-out.c:55
vDisplayHeader
void vDisplayHeader(trace *spCtx)
Display the trace header.
Definition: trace-out.c:98
html_info::cpOutput
char * cpOutput
Pointer to a buffer to build output in.
Definition: trace-out.c:54
ID_AEN
#define ID_AEN
anchor - end of string
Definition: parser.h:62
APG_FALSE
#define APG_FALSE
Definition: apg.h:292
APG Version 7.0 is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.