Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
udtlib.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 * *************************************************************************************/
44 #include <stdio.h>
45 #include "../../library/lib.h"
46 #include "./sip-1.h"
47 
48 #define isalphanum(c) (((c) >= 97 && (c) <= 122) || ((c) >= 48 && (c) <= 57) || ((c) >= 65 && (c) <= 90))
49 #define ishexdigit(c) (((c) >= 48 && (c) <= 57) || ((c) >= 65 && (c) <= 70) || ((c) >= 97 && (c) <= 102))
50 
51 //paramchar = param-unreserved / unreserved / escaped
52 //;unreserved = u_alphanum / mark
53 //;mark = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")"
54 //;escaped = "%" HEXDIG HEXDIG
55 //param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
56 static abool bParamchar(achar acChar){
57  if(isalphanum(acChar)){
58  // alphanum
59  return APG_TRUE;
60  }
61  switch(acChar){
62  // mark
63  case 33:
64  case 39:
65  case 40:
66  case 41:
67  case 42:
68  case 45:
69  case 46:
70  case 95:
71  case 126:
72  // param-unreserved
73  case 36:
74  case 43:
75  case 47:
76  case 58:
77  case 63:
78  case 91:
79  case 93:
80  return APG_TRUE;
81  default:
82  break;
83  }
84  return APG_FALSE;
85  // escaped
86 }
87 static abool bEscaped(achar acChar1, achar acChar2, achar acChar3){
88  if(acChar1 != 37){
89  return APG_FALSE;
90  }
91  if(ishexdigit(acChar2)){
92  if(ishexdigit(acChar3)){
93  return APG_TRUE;
94  }
95  }
96  return APG_FALSE;
97 }
98 
99 void u_Digit(callback_data* spData){
100  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
101  const achar* acpEnd = spData->acpString + spData->uiStringLength;
102  spData->uiCallbackState = ID_NOMATCH;
103  spData->uiCallbackPhraseLength = 0;
104  if(acpChar < acpEnd){
105  if(*acpChar >= 48 && *acpChar <= 57){
106  spData->uiCallbackState = ID_MATCH;
107  spData->uiCallbackPhraseLength = 1;
108  }
109  }
110 }
111 void u_Digit1(callback_data* spData){
112  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
113  const achar* acpEnd = spData->acpString + spData->uiStringLength;
114  aint uiLen = 0;
115  while(acpChar < acpEnd){
116  if(*acpChar >= 48 && *acpChar <= 57){
117  uiLen++;
118  acpChar++;
119  }else{
120  break;
121  }
122  }
123  if(uiLen){
124  spData->uiCallbackState = ID_MATCH;
125  spData->uiCallbackPhraseLength = uiLen;
126  }else{
127  spData->uiCallbackState = ID_NOMATCH;
128  spData->uiCallbackPhraseLength = 0;
129  }
130 }
142  achar acChar;
143  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
144  const achar* acpEnd = spData->acpString + spData->uiStringLength;
145  aint uiLen = 0;
146  spData->uiCallbackState = ID_NOMATCH;
147  spData->uiCallbackPhraseLength = 0;
148  while(APG_TRUE){
149  if(acpChar == acpEnd){
150  // end of string
151  break;
152  }
153  acChar = *acpChar;
154  if(!isalphanum(acChar)){
155  // first character is not alphanum
156  break;
157  }
158  uiLen++;
159  acpChar++;
160  while(acpChar < acpEnd){
161  acChar = *acpChar;
162  if(isalphanum(acChar) || acChar == 45){
163  uiLen++;
164  acpChar++;
165  }else{
166  break;
167  }
168  }
169  if(acpChar[-1] == 45){
170  // last character cannot be hyphen
171  break;
172  }
173  // must be followed by .alphanum
174  if(acpChar < acpEnd && *acpChar == 46){
175  acpChar++;
176  acChar = *acpChar;
177  if(acpChar < acpEnd && isalphanum(acChar)){
178  // success - it's a domainlabel
179  spData->uiCallbackState = ID_MATCH;
180  spData->uiCallbackPhraseLength = uiLen;
181  break;
182  }
183  }
184  break;
185  }
186 }
187 
196  spData->uiCallbackState = ID_MATCH;
197  spData->uiCallbackPhraseLength = spData->uiStringLength - spData->uiParserOffset;
198 }
199 
207 void u_CRLF(callback_data* spData){
208  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
209  const achar* acpEnd = spData->acpString + spData->uiStringLength;
210  aint uiLen = 0;
211  if(acpChar < acpEnd){
212  if(*acpChar == 13){
213  uiLen++;
214  acpChar++;
215  if((acpChar < acpEnd) && *acpChar == 10){
216  uiLen++;
217  }
218  }else if(*acpChar == 10){
219  uiLen++;
220  }
221  }
222  if(uiLen){
223  spData->uiCallbackState = ID_MATCH;
224  spData->uiCallbackPhraseLength = uiLen;
225  }else{
226  spData->uiCallbackState = ID_NOMATCH;
227  spData->uiCallbackPhraseLength = 0;
228  }
229  return;
230 }
231 
238 void u_LWS(callback_data* spData){
239  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
240  const achar* acpEnd = spData->acpString + spData->uiStringLength;
241  aint uiLen = 0;
242  aint uiLenCR = 0;
243  aint uiLenWS = 0;
244  while(acpChar < acpEnd){
245  if((*acpChar == 32) || (*acpChar == 9)){
246  uiLen++;
247  acpChar++;
248  }else{
249  break;
250  }
251  }
252  if(acpChar < acpEnd){
253  if(*acpChar == 13){
254  uiLenCR++;
255  acpChar++;
256  if((acpChar < acpEnd) && *acpChar == 10){
257  uiLenCR++;
258  }
259  }else if(*acpChar == 10){
260  uiLenCR++;
261  acpChar++;
262  }
263  }
264  if(uiLenCR){
265  while(acpChar < acpEnd){
266  if((*acpChar == 32) || (*acpChar == 9)){
267  uiLenWS++;
268  acpChar++;
269  }else{
270  break;
271  }
272  }
273  if(uiLenWS){
274  spData->uiCallbackState = ID_MATCH;
275  spData->uiCallbackPhraseLength = uiLen + uiLenCR + uiLenWS;
276  }else{
277  spData->uiCallbackState = ID_NOMATCH;
278  spData->uiCallbackPhraseLength = 0;
279  }
280  }else{
281  if(uiLen){
282  spData->uiCallbackState = ID_MATCH;
283  spData->uiCallbackPhraseLength = uiLen;
284  }else{
285  spData->uiCallbackState = ID_NOMATCH;
286  spData->uiCallbackPhraseLength = 0;
287  }
288  }
289  return;
290 }
296 void e_SWS(callback_data* spData){
297  u_LWS(spData);
298  if(spData->uiCallbackPhraseLength == 0){
299  spData->uiCallbackState = ID_MATCH;
300  }
301 }
302 
303 void u_WSP(callback_data* spData){
304  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
305  const achar* acpEnd = spData->acpString + spData->uiStringLength;
306  spData->uiCallbackState = ID_NOMATCH;
307  spData->uiCallbackPhraseLength = 0;
308  if(acpChar < acpEnd){
309  if((*acpChar == 32) || (*acpChar == 9)){
310  spData->uiCallbackState = ID_MATCH;
311  spData->uiCallbackPhraseLength = 1;
312  }
313  }
314 }
316  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
317  const achar* acpEnd = spData->acpString + spData->uiStringLength;
318  achar acChar;
319  aint uiLen = 0;
320  while(acpChar < acpEnd){
321  acChar = *acpChar;
322  if(isalphanum(acChar)){
323  uiLen++;
324  acpChar++;
325  }else{
326  break;
327  }
328  }
329  spData->uiCallbackState = ID_MATCH;
330  spData->uiCallbackPhraseLength = uiLen;
331 }
333  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
334  const achar* acpEnd = spData->acpString + spData->uiStringLength;
335  achar acChar;
336  aint uiLen = 0;
337  while(acpChar < acpEnd){
338  acChar = *acpChar;
339  if(isalphanum(acChar)){
340  uiLen++;
341  acpChar++;
342  }else{
343  break;
344  }
345  }
346  if(uiLen){
347  spData->uiCallbackState = ID_MATCH;
348  spData->uiCallbackPhraseLength = uiLen;
349  }else{
350  spData->uiCallbackState = ID_NOMATCH;
351  spData->uiCallbackPhraseLength = 0;
352  }
353 }
354 void u_alphanum(callback_data* spData){
355  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
356  const achar* acpEnd = spData->acpString + spData->uiStringLength;
357  achar acChar = *acpChar;
358  if((acpChar < acpEnd) && isalphanum(acChar)){
359  spData->uiCallbackState = ID_MATCH;
360  spData->uiCallbackPhraseLength = 1;
361  }else{
362  spData->uiCallbackState = ID_NOMATCH;
363  spData->uiCallbackPhraseLength = 0;
364  }
365 }
366 void u_ALPHA(callback_data* spData){
367  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
368  const achar* acpEnd = spData->acpString + spData->uiStringLength;
369  achar acChar = *acpChar;
370  if((acpChar < acpEnd) && ((acChar >= 97 && acChar <= 122) || (acChar >= 65 && acChar <= 90))){
371  spData->uiCallbackState = ID_MATCH;
372  spData->uiCallbackPhraseLength = 1;
373  }else{
374  spData->uiCallbackState = ID_NOMATCH;
375  spData->uiCallbackPhraseLength = 0;
376  }
377 }
378 
380  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
381  const achar* acpEnd = spData->acpString + spData->uiStringLength;
382  aint uiLen = 0;
383  while(acpChar < acpEnd){
384  if(bParamchar(*acpChar)){
385  uiLen++;
386  acpChar++;
387  continue;
388  }
389  if((acpChar + 3) < acpEnd){
390  if(bEscaped(acpChar[0], acpChar[1], acpChar[2])){
391  uiLen += 3;
392  acpChar += 3;
393  continue;
394  }
395  }
396  break;
397  }
398  if(uiLen){
399  spData->uiCallbackState = ID_MATCH;
400  spData->uiCallbackPhraseLength = uiLen;
401  }else{
402  spData->uiCallbackState = ID_NOMATCH;
403  spData->uiCallbackPhraseLength = 0;
404  }
405 }
406 
407 //;unreserved = u_alphanum / mark
408 //mark = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")"
410  const achar* acpChar = &spData->acpString[spData->uiParserOffset];
411  const achar* acpEnd = spData->acpString + spData->uiStringLength;
412  achar acChar;
413  if(acpChar < acpEnd){
414  acChar = *acpChar;
415  if(isalphanum(acChar)){
416  spData->uiCallbackState = ID_MATCH;
417  spData->uiCallbackPhraseLength = 1;
418  return;
419  }
420  switch(acChar){
421  // mark
422  case 33:
423  case 39:
424  case 40:
425  case 41:
426  case 42:
427  case 45:
428  case 46:
429  case 95:
430  case 126:
431  spData->uiCallbackState = ID_MATCH;
432  spData->uiCallbackPhraseLength = 1;
433  return;
434  default:
435  break;
436  }
437  }
438  spData->uiCallbackState = ID_NOMATCH;
439  spData->uiCallbackPhraseLength = 0;
440 }
441 
447 void vSip1UdtCallbacks(void* vpParserCtx){
448  aint ui;
450  memset((void*)cb, 0, sizeof(cb));
454  cb[SIP_1_E_SWS] = e_SWS;
455  cb[SIP_1_U_CRLF] = u_CRLF;
457  cb[SIP_1_U_DIGIT] = u_Digit;
458  cb[SIP_1_U_DIGIT1] = u_Digit1;
459  cb[SIP_1_U_LWS] = u_LWS;
460  cb[SIP_1_U_WSP] = u_WSP;
462  cb[SIP_1_U_ALPHA] = u_ALPHA;
465  for(ui = 0; ui < (aint)UDT_COUNT_SIP_1; ui++){
466  vParserSetUdtCallback(vpParserCtx, ui, cb[ui]);
467  }
468 }
469 
470 //static void vLWSPhrase(const achar* acpBeg, aint uiOffset, aint uiLen, char* cpTitle){
471 // char caBuf[2*uiLen + 1];
472 // char* cpBuf = caBuf;
473 // const achar* acpChar = acpBeg + uiOffset;
474 // const achar* acpEnd = acpChar + uiLen;
475 // while(acpChar < acpEnd){
476 // switch(*acpChar){
477 // case 9:
478 // *cpBuf++ = '\\';
479 // *cpBuf++ = 't';
480 // break;
481 // case 10:
482 // *cpBuf++ = '\\';
483 // *cpBuf++ = 'n';
484 // break;
485 // case 13:
486 // *cpBuf++ = '\\';
487 // *cpBuf++ = 'r';
488 // break;
489 // case 32:
490 // *cpBuf++ = 's';
491 // break;
492 // default:
493 // *cpBuf++ = (char)*acpChar++;
494 // break;
495 // }
496 // acpChar++;
497 // }
498 // *cpBuf = 0;
499 // printf("%s: offset: %"PRIuMAX": length: %"PRIuMAX": phrase: %s\n", cpTitle, (luint)uiOffset, (luint)uiLen, caBuf);
500 //
501 //}
502 //static void vPrintPhrase(const achar* acpBeg, aint uiOffset, aint uiLen, char* cpTitle){
503 // char caBuf[2*uiLen + 1];
504 // char* cpBuf = caBuf;
505 // const achar* acpChar = acpBeg + uiOffset;
506 // const achar* acpEnd = acpChar + uiLen;
507 // while(acpChar < acpEnd){
508 // *cpBuf++ = (char)*acpChar++;
509 // }
510 // *cpBuf = 0;
511 // printf("%s: offset: %"PRIuMAX": length: %"PRIuMAX": phrase: %s\n", cpTitle, (luint)uiOffset, (luint)uiLen, caBuf);
512 //
513 //}
u_Alphanum1
void u_Alphanum1(callback_data *spData)
Definition: udtlib.c:332
u_ALPHA
void u_ALPHA(callback_data *spData)
Definition: udtlib.c:366
vSip1UdtCallbacks
void vSip1UdtCallbacks(void *vpParserCtx)
Set the UDT callback functions for the SIP2.bnf grammar to their respective parse tree nodes.
Definition: udtlib.c:447
u_DomainLabel
void u_DomainLabel(callback_data *spData)
Evaluates the lower elements of a host name.
Definition: udtlib.c:141
ishexdigit
#define ishexdigit(c)
Definition: udtlib.c:49
callback_data::uiParserOffset
aint uiParserOffset
[read only] Offset from acpString to the first character to match
Definition: parser.h:160
callback_data::acpString
const achar * acpString
[read only] Pointer to the input sub-string,
Definition: parser.h:156
achar
uint_fast8_t achar
achar is the type for the parser's alphabet characters.
Definition: apg.h:91
u_WSP
void u_WSP(callback_data *spData)
Definition: udtlib.c:303
parser_callback
void(* parser_callback)(callback_data *spData)
User-written callback function prototype.
Definition: parser.h:178
u_CRLF
void u_CRLF(callback_data *spData)
Evaluates the line end character sequence.
Definition: udtlib.c:207
vParserSetUdtCallback
void vParserSetUdtCallback(void *vpCtx, aint uiUdtId, parser_callback pfnCallback)
Set a call back function for a specific UDT.
Definition: parser.c:407
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
u_Digit
void u_Digit(callback_data *spData)
Definition: udtlib.c:99
callback_data::uiCallbackState
aint uiCallbackState
[input/output] Rule name (RNM) callback functions: If ID_ACTIVE, the parser takes no action....
Definition: parser.h:139
e_MessageBody
void e_MessageBody(callback_data *spData)
Evaluates the message body.
Definition: udtlib.c:195
SIP_1_U_LWS
#define SIP_1_U_LWS
Definition: sip-1.h:354
u_Digit1
void u_Digit1(callback_data *spData)
Definition: udtlib.c:111
SIP_1_U_PARAMCHAR1
#define SIP_1_U_PARAMCHAR1
Definition: sip-1.h:355
u_unreserved
void u_unreserved(callback_data *spData)
Definition: udtlib.c:409
SIP_1_U_DIGIT
#define SIP_1_U_DIGIT
Definition: sip-1.h:351
callback_data::uiCallbackPhraseLength
aint uiCallbackPhraseLength
[input/output] The phrase length of the matched phrase if the callback function returns ID_MATCH.
Definition: parser.h:145
ID_MATCH
#define ID_MATCH
indicates a matched phrase parser state on return from parse tree below this node
Definition: parser.h:73
callback_data
The data struct passed to each callback function.
Definition: parser.h:134
SIP_1_U_ALPHANUM1
#define SIP_1_U_ALPHANUM1
Definition: sip-1.h:349
u_alphanum
void u_alphanum(callback_data *spData)
Definition: udtlib.c:354
e_Alphanum0
void e_Alphanum0(callback_data *spData)
Definition: udtlib.c:315
APG_TRUE
#define APG_TRUE
Definition: apg.h:291
e_SWS
void e_SWS(callback_data *spData)
Optional linear white space. (See u_LWS.)
Definition: udtlib.c:296
SIP_1_U_CRLF
#define SIP_1_U_CRLF
Definition: sip-1.h:350
SIP_1_E_ALPHANUM0
#define SIP_1_E_ALPHANUM0
Definition: sip-1.h:344
abool
uint8_t abool
abool is the APG bool type.
Definition: apg.h:140
SIP_1_E_SWS
#define SIP_1_E_SWS
Definition: sip-1.h:346
ID_NOMATCH
#define ID_NOMATCH
indicates that no phrase was matched on return from parse tree below this node
Definition: parser.h:74
u_paramchar1
void u_paramchar1(callback_data *spData)
Definition: udtlib.c:379
isalphanum
#define isalphanum(c)
Definition: udtlib.c:48
SIP_1_U_WSP
#define SIP_1_U_WSP
Definition: sip-1.h:357
SIP_1_E_MESSAGEBODY
#define SIP_1_E_MESSAGEBODY
Definition: sip-1.h:345
SIP_1_U_UNRESERVED
#define SIP_1_U_UNRESERVED
Definition: sip-1.h:356
callback_data::uiStringLength
aint uiStringLength
[read only] The input string length.
Definition: parser.h:157
SIP_1_U_ALPHANUM
#define SIP_1_U_ALPHANUM
Definition: sip-1.h:348
SIP_1_U_DOMAINLABEL
#define SIP_1_U_DOMAINLABEL
Definition: sip-1.h:353
UDT_COUNT_SIP_1
#define UDT_COUNT_SIP_1
Definition: sip-1.h:358
sip-1.h
SIP_1_U_ALPHA
#define SIP_1_U_ALPHA
Definition: sip-1.h:347
u_LWS
void u_LWS(callback_data *spData)
Linear white space. White space with possible line breaks allowed.
Definition: udtlib.c:238
SIP_1_U_DIGIT1
#define SIP_1_U_DIGIT1
Definition: sip-1.h:352
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.