Used to ensure that an AI component conforms to the North American Coupon Code (NACC) specification, as carried in AI (8110).
185{
186
188 size_t pos;
189 int vli;
190 const char *p, *q;
191 char expiry_date[7] = {0};
192 int expiry_set = 0;
193 char gcp[14] = {0};
194
195 assert(data);
196
197
198
199
200
201 if ((pos = strspn(data, "0123456789")) != strlen(data))
204 pos,
205 1
206 );
207
208 p = data;
209 q = data + strlen(data);
210
211
212
213
214
215
216
217
218
219 if (p == q)
222 0,
223 (size_t)(q - data)
224 );
225 if (*p > '6')
228 (size_t)(p - data),
229 1
230 );
231 vli = *p - '0' + 6;
232
233 if (q - ++p < vli)
236 (p == q) ? 0 : (size_t)(p - data),
237 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
238 );
239
240
241
242
243
244 strncpy(gcp, p, (size_t)vli);
246
250
253 ret,
254 (size_t)(p - data),
255 (size_t)vli
256 );
257
258 p += vli;
259
260
261
262
263
264
265 if (q - p < 6)
268 (p == q) ? 0 : (size_t)(p - data),
269 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
270 );
271
272 p += 6;
273
274
275
276
277
278
279
280
281
282 if (p == q)
285 0,
286 (size_t)(q - data)
287 );
288 if (*p < '1' || *p > '5')
291 (size_t)(p - data),
292 1
293 );
294 vli = *p - '0';
295
296 if (q - ++p < vli)
299 (p == q) ? 0 : (size_t)(p - data),
300 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
301 );
302
303 p += vli;
304
305
306
307
308
309
310
311
312
313 if (p == q)
316 0,
317 (size_t)(q - data)
318 );
319 if (*p < '1' || *p > '5')
322 (size_t)(p - data),
323 1
324 );
325 vli = *p - '0';
326
327 if (q - ++p < vli)
330 (p == q) ? 0 : (size_t)(p - data),
331 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
332 );
333
334 p += vli;
335
336
337
338
339
340
341
342
343
344 if (p == q)
347 0,
348 (size_t)(q - data)
349 );
350
351 if (*p > '4' && *p != '9')
354 (size_t)(p - data),
355 1
356 );
357
358
359
360
361
362
363 if (q - ++p < 3)
366 (p == q) ? 0 : (size_t)(p - data),
367 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
368 );
369
370 p += 3;
371
372
373
374
375
376
377
378
379
380 if (p < q && *p == '1') {
381
382
383
384
385
386
387
388
389 if (++p == q)
392 0,
393 (size_t)(q - data)
394 );
395
396 if (*p > '3')
399 (size_t)(p - data),
400 1
401 );
402
403
404
405
406
407
408
409
410
411
412 if (++p == q)
415 0,
416 (size_t)(q - data)
417 );
418 if (*p < '1' || *p > '5')
421 (size_t)(p - data),
422 1
423 );
424 vli = *p - '0';
425
426 if (q - ++p < vli)
429 (p == q) ? 0 : (size_t)(p - data),
430 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
431 );
432
433 p += vli;
434
435
436
437
438
439
440
441
442
443 if (p == q)
446 0,
447 (size_t)(q - data)
448 );
449
450 if (*p > '4' && *p != '9')
453 (size_t)(p - data),
454 1
455 );
456
457
458
459
460
461
462
463 if (q - ++p < 3)
466 (p == q) ? 0 : (size_t)(p - data),
467 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
468 );
469
470 p += 3;
471
472
473
474
475
476
477
478
479
480
481 if (p == q)
484 0,
485 (size_t)(q - data)
486 );
487 if (*p > '6' && *p != '9')
490 (size_t)(p - data),
491 1
492 );
493 vli = (*p != '9') ? *p - '0' + 6 : 0;
494
495 if (q - ++p < vli)
498 (p == q) ? 0 : (size_t)(p - data),
499 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
500 );
501
502
503
504
505
506 strncpy(gcp, p, (size_t)vli);
508
512
515 ret,
516 (size_t)(p - data),
517 (size_t)vli
518 );
519
520 p += vli;
521
522 }
523
524
525
526
527
528
529
530
531
532 if (p < q && *p == '2') {
533
534
535
536
537
538
539
540
541
542 if (++p == q)
545 0,
546 (size_t)(q - data)
547 );
548 if (*p < '1' || *p > '5')
551 (size_t)(p - data),
552 1
553 );
554 vli = *p - '0';
555
556 if (q - ++p < vli)
559 (p == q) ? 0 : (size_t)(p - data),
560 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
561 );
562
563 p += vli;
564
565
566
567
568
569
570
571
572
573 if (p == q)
576 0,
577 (size_t)(q - data)
578 );
579
580 if (*p > '4' && *p != '9')
583 (size_t)(p - data),
584 1
585 );
586
587
588
589
590
591
592
593 if (q - ++p < 3)
596 (p == q) ? 0 : (size_t)(p - data),
597 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
598 );
599
600 p += 3;
601
602
603
604
605
606
607
608
609
610
611 if (p == q)
614 0,
615 (size_t)(q - data)
616 );
617 if (*p > '6' && *p != '9')
620 (size_t)(p - data),
621 1
622 );
623 vli = (*p != '9') ? *p - '0' + 6 : 0;
624
625 if (q - ++p < vli)
628 (p == q) ? 0 : (size_t)(p - data),
629 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
630 );
631
632
633
634
635
636 strncpy(gcp, p, (size_t)vli);
638
642
645 ret,
646 (size_t)(p - data),
647 (size_t)vli
648 );
649
650 p += vli;
651
652 }
653
654
655
656
657
658
659
660
661
662 if (p < q && *p == '3') {
663
664
665
666
667
668 if (q - ++p < 6)
671 (p == q) ? 0 : (size_t)(p - data),
672 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
673 );
674
675 memcpy(expiry_date, p, 6);
677
684
688 (size_t)(p - data),
689 6
690 );
691
692 p += 6;
693
694 expiry_set = 1;
695
696 }
697
698
699
700
701
702
703
704
705
706 if (p < q && *p == '4') {
707
708 char start_date[7] = {0};
709
710
711
712
713
714 if (q - ++p < 6)
717 (p == q) ? 0 : (size_t)(p - data),
718 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
719 );
720
721 memcpy(start_date, p, 6);
723
730
734 (size_t)(p - data),
735 6
736 );
737
738
739
740
741
742
743 if (expiry_set && strcmp(start_date, expiry_date) > 0)
746 (size_t)(p - data - 8),
747 14
748 );
749
750 p += 6;
751
752 }
753
754
755
756
757
758
759
760
761
762 if (p < q && *p == '5') {
763
764
765
766
767
768
769 if (++p == q)
772 0,
773 (size_t)(q - data)
774 );
775 vli = *p - '0' + 6;
776
777 if (q - ++p < vli)
780 (p == q) ? 0 : (size_t)(p - data),
781 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
782 );
783
784 p += vli;
785
786 }
787
788
789
790
791
792
793
794
795
796 if (p < q && *p == '6') {
797
798
799
800
801
802
803
804
805 if (++p == q)
808 0,
809 (size_t)(q - data)
810 );
811 if (*p < '1' || *p > '7')
814 (size_t)(p - data),
815 1
816 );
817 vli = *p - '0' + 6;
818
819 if (q - ++p < vli)
822 (p == q) ? 0 : (size_t)(p - data),
823 (p == q) ? (size_t)(q - data) : (size_t)(q - p)
824 );
825
826
827
828
829
830 strncpy(gcp, p, (size_t)vli);
832
836
839 ret,
840 (size_t)(p - data),
841 (size_t)vli
842 );
843
844 p += vli;
845
846 }
847
848
849
850
851
852
853
854
855
856 if (p < q && *p == '9') {
857
858
859
860
861
862
863
864
865 if (++p == q)
868 0,
869 (size_t)(q - data)
870 );
871 if (*p != '0' && *p != '1' && *p != '2' && *p != '5' && *p != '6')
874 (size_t)(p - data),
875 1
876 );
877
878
879
880
881
882
883
884
885 if (++p == q)
888 0,
889 (size_t)(q - data)
890 );
891 if (*p > '2')
894 (size_t)(p - data),
895 1
896 );
897
898
899
900
901
902
903
904 if (++p == q)
907 0,
908 (size_t)(q - data)
909 );
910
911
912
913
914
915
916
917
918 if (++p == q)
921 0,
922 (size_t)(q - data)
923 );
924 if (*p != '0' && *p != '1')
927 (size_t)(p - data),
928 1
929 );
930
931 p++;
932
933 }
934
935
936
937
938
939 if (p != q)
942 (size_t)(p - data),
943 (size_t)(q - p)
944 );
945
947
948}
#define GS1_LINTER_RETURN_ERROR(error, position, length)
Return from a linter indicating that a problem was detected with the given data.
Definition gs1syntaxdictionary-utils.h:77
#define GS1_LINTER_RETURN_OK
Return from a linter indicating that no problem was detected with the given data.
Definition gs1syntaxdictionary-utils.h:62
GS1_SYNTAX_DICTIONARY_API gs1_lint_err_t gs1_lint_yymmdd(const char *data, size_t *err_pos, size_t *err_len)
Definition lint_yymmdd.c:53
gs1_lint_err_t
Linter return codes other than GS1_LINTER_OK indicate an error condition.
Definition gs1syntaxdictionary.h:76
@ GS1_LINTER_ILLEGAL_DAY
The date contains an illegal day of the month.
Definition gs1syntaxdictionary.h:114
@ GS1_LINTER_COUPON_TRUNCATED_2ND_PURCHASE_FAMILY_CODE
The coupon's second purchase Family Code is shorter than the required three digits.
Definition gs1syntaxdictionary.h:150
@ GS1_LINTER_COUPON_TRUNCATED_RETAILER_GCP_OR_GLN
The coupon's Retailer GCP/GLN is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:170
@ GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_REQUIREMENT_LENGTH
The coupon's second purchase Requirement VLI must be "1" to "5".
Definition gs1syntaxdictionary.h:146
@ GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_REQUIREMENT_VLI
The coupon's third purchase Requirement VLI is missing.
Definition gs1syntaxdictionary.h:154
@ GS1_LINTER_COUPON_MISSING_RETAILER_GCP_OR_GLN_VLI
The coupon's Retailer GCP/GLN VLI is missing.
Definition gs1syntaxdictionary.h:168
@ GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_REQUIREMENT_LENGTH
The coupon's third purchase Requirement VLI must be "1" to "5".
Definition gs1syntaxdictionary.h:155
@ GS1_LINTER_COUPON_MISSING_1ST_PURCHASE_REQUIREMENT_VLI
The coupon's primary purchase Requirement VLI is missing.
Definition gs1syntaxdictionary.h:137
@ GS1_LINTER_COUPON_INVALID_SAVE_VALUE_CODE
The coupon's Save Value Code must be "0", "1", "2", "5" or "6".
Definition gs1syntaxdictionary.h:172
@ GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_GCP_LENGTH
The coupon's second purchase GS1 Company Prefix VLI must be "0" to "6" or "9".
Definition gs1syntaxdictionary.h:152
@ GS1_LINTER_COUPON_TRUNCATED_1ST_PURCHASE_FAMILY_CODE
The coupon's primary purchase Family Code is shorter than the required three digits.
Definition gs1syntaxdictionary.h:142
@ GS1_LINTER_COUPON_INVALID_SAVE_VALUE_APPLIES_TO_ITEM
The coupon's Save Value Applies to Item must be "0" to "2".
Definition gs1syntaxdictionary.h:174
@ GS1_LINTER_COUPON_MISSING_SAVE_VALUE_APPLIES_TO_ITEM
The coupon's Save Value Applies to Item is missing.
Definition gs1syntaxdictionary.h:173
@ GS1_LINTER_COUPON_TRUNCATED_GCP
The coupon's primary GS1 Company Prefix is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:133
@ GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_REQUIREMENT_CODE
The coupon's third purchase Requirement Code is missing.
Definition gs1syntaxdictionary.h:157
@ GS1_LINTER_COUPON_TRUNCATED_3RD_PURCHASE_REQUIREMENT
The coupon's third purchase Requirement is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:156
@ GS1_LINTER_DATE_TOO_LONG
The date is too long for YYMMDD format.
Definition gs1syntaxdictionary.h:106
@ GS1_LINTER_COUPON_TRUNCATED_SAVE_VALUE
The coupon's Save Value is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:136
@ GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_REQUIREMENT_CODE
The coupon's second purchase Requirement Code must be "0" to "4" or "9".
Definition gs1syntaxdictionary.h:149
@ GS1_LINTER_GCP_DATASOURCE_OFFLINE
The data source for GCP lookups is offline.
Definition gs1syntaxdictionary.h:87
@ GS1_LINTER_COUPON_MISSING_SERIAL_NUMBER_VLI
The coupon's Serial Number VLI is missing.
Definition gs1syntaxdictionary.h:129
@ GS1_LINTER_COUPON_TRUNCATED_1ST_PURCHASE_REQUIREMENT
The coupon's primary purchase Requirement is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:139
@ GS1_LINTER_COUPON_MISSING_1ST_PURCHASE_REQUIREMENT_CODE
The coupon's primary purchase Requirement Code is missing.
Definition gs1syntaxdictionary.h:140
@ GS1_LINTER_ILLEGAL_MONTH
The date contains an illegal month of the year.
Definition gs1syntaxdictionary.h:113
@ GS1_LINTER_COUPON_MISSING_GCP_VLI
The coupon's primary GS1 Company Prefix VLI is missing.
Definition gs1syntaxdictionary.h:131
@ GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_REQUIREMENT_CODE
The coupon's second purchase Requirement Code is missing.
Definition gs1syntaxdictionary.h:148
@ GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_REQUIREMENT_VLI
The coupon's second purchase Requirement VLI is missing.
Definition gs1syntaxdictionary.h:145
@ GS1_LINTER_COUPON_TRUNCATED_3RD_PURCHASE_FAMILY_CODE
The coupon's third purchase Family Code is shorter than the required three digits.
Definition gs1syntaxdictionary.h:159
@ GS1_LINTER_COUPON_TRUNCATED_SERIAL_NUMBER
The coupon's Serial Number is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:130
@ GS1_LINTER_COUPON_TOO_SHORT_FOR_START_DATE
The coupon's start date is too short to YYMMDD format.
Definition gs1syntaxdictionary.h:165
@ GS1_LINTER_COUPON_INVALID_START_DATE
The coupon's start date is invalid.
Definition gs1syntaxdictionary.h:166
@ GS1_LINTER_COUPON_INVALID_SAVE_VALUE_LENGTH
The coupon's Save Value VLI must be "1" to "5".
Definition gs1syntaxdictionary.h:135
@ GS1_LINTER_COUPON_TRUNCATED_OFFER_CODE
The coupon's Offer Code is shorter than the required six digits.
Definition gs1syntaxdictionary.h:128
@ GS1_LINTER_COUPON_MISSING_ADDITIONAL_PURCHASE_RULES_CODE
The coupon's Additional Purchase Rules Code is missing.
Definition gs1syntaxdictionary.h:143
@ GS1_LINTER_COUPON_INVALID_DONT_MULTIPLY_FLAG
The coupon's Don't Multiply Flag must be "0" or "1".
Definition gs1syntaxdictionary.h:177
@ GS1_LINTER_COUPON_TRUNCATED_2ND_PURCHASE_GCP
The coupon's second purchase GS1 Company Prefix is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:153
@ GS1_LINTER_COUPON_MISSING_STORE_COUPON_FLAG
The coupon's Store Coupon Flag is missing.
Definition gs1syntaxdictionary.h:175
@ GS1_LINTER_COUPON_EXCESS_DATA
The coupon contains excess data after the recognised optional fields.
Definition gs1syntaxdictionary.h:178
@ GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_GCP_VLI
The coupon's third purchase GS1 Company Prefix VLI is missing.
Definition gs1syntaxdictionary.h:160
@ GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_GCP_VLI
The coupon's second purchase GS1 Company Prefix VLI is missing.
Definition gs1syntaxdictionary.h:151
@ GS1_LINTER_COUPON_TOO_SHORT_FOR_EXPIRATION_DATE
The coupon's expiration date is too short for YYMMDD format.
Definition gs1syntaxdictionary.h:163
@ GS1_LINTER_COUPON_INVALID_GCP_LENGTH
The coupon's primary GS1 Company Prefix VLI must be "0" to "6".
Definition gs1syntaxdictionary.h:132
@ GS1_LINTER_DATE_TOO_SHORT
The date is too short for YYMMDD format.
Definition gs1syntaxdictionary.h:105
@ GS1_LINTER_COUPON_INVALID_EXIPIRATION_DATE
The coupon's expiration date is invalid.
Definition gs1syntaxdictionary.h:164
@ GS1_LINTER_COUPON_MISSING_SAVE_VALUE_VLI
The coupon's Save Value VLI is missing.
Definition gs1syntaxdictionary.h:134
@ GS1_LINTER_COUPON_INVALID_1ST_PURCHASE_REQUIREMENT_CODE
The coupon's primary purchase Requirement Code must be "0" to "4" or "9".
Definition gs1syntaxdictionary.h:141
@ GS1_LINTER_COUPON_TRUNCATED_2ND_PURCHASE_REQUIREMENT
The coupon's second purchase Requirement is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:147
@ GS1_LINTER_OK
No issues were detected by the linter.
Definition gs1syntaxdictionary.h:77
@ GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_REQUIREMENT_CODE
The coupon's third purchase Requirement Code must be "0" to "4" or "9".
Definition gs1syntaxdictionary.h:158
@ GS1_LINTER_COUPON_EXPIRATION_BEFORE_START
The coupon's expiration date preceed the start date.
Definition gs1syntaxdictionary.h:167
@ GS1_LINTER_COUPON_INVALID_ADDITIONAL_PURCHASE_RULES_CODE
The coupon's Additional Purchase Rules Code must be "0" to "3".
Definition gs1syntaxdictionary.h:144
@ GS1_LINTER_COUPON_INVALID_1ST_PURCHASE_REQUIREMENT_LENGTH
The coupon's primary purchase Requirement VLI must be "1" to "5".
Definition gs1syntaxdictionary.h:138
@ GS1_LINTER_INVALID_GCP_PREFIX
The GS1 Company Prefix is invalid.
Definition gs1syntaxdictionary.h:89
@ GS1_LINTER_COUPON_TRUNCATED_3RD_PURCHASE_GCP
The coupon's third purchase GS1 Company Prefix is shorter than what is indicated by its VLI.
Definition gs1syntaxdictionary.h:162
@ GS1_LINTER_NON_DIGIT_CHARACTER
A non-digit character was found where a digit is expected.
Definition gs1syntaxdictionary.h:78
@ GS1_LINTER_COUPON_MISSING_DONT_MULTIPLY_FLAG
The coupon's Don't Multiply Flag is missing.
Definition gs1syntaxdictionary.h:176
@ GS1_LINTER_COUPON_MISSING_SAVE_VALUE_CODE
The coupon's Save Value Code is missing.
Definition gs1syntaxdictionary.h:171
@ GS1_LINTER_COUPON_INVALID_RETAILER_GCP_OR_GLN_LENGTH
The coupon's Retailer GCP/GLN VLI must be "1" to "7".
Definition gs1syntaxdictionary.h:169
@ GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_GCP_LENGTH
The coupon's third purchase GS1 Company Prefix VLI must be "0" to "6" or "9".
Definition gs1syntaxdictionary.h:161
GS1_SYNTAX_DICTIONARY_API gs1_lint_err_t gs1_lint_key(const char *data, size_t *err_pos, size_t *err_len)
Definition lint_key.c:96