GS1 Syntax Dictionary: Linter reference
A reference to the AI component linter routines referred to by the GS1 Syntax Dictionary.
lint_couponcode.c File Reference

Purpose

The couponcode linter ensures that the data conforms to the original North American Coupon Code (NACC) specification, as carried in AI (8110).

Remarks
Refer to the document "North American Coupon Application Guideline Using GS1 DataBar Expanded Symbols" for a description of the GS1 U.S. coupon code data content.

Functional Description

◆ gs1_lint_couponcode()

GS1_SYNTAX_DICTIONARY_API gs1_lint_err_t gs1_lint_couponcode ( const char *const  data,
size_t *const  err_pos,
size_t *const  err_len 
)

Used to ensure that an AI component conforms to the North American Coupon Code (NACC) specification, as carried in AI (8110).

Parameters
[in]dataPointer to the null-terminated data to be linted. Must not be NULL.
[out]err_posTo facilitate error highlighting, the start position of the bad data is written to this pointer, if not NULL.
[out]err_lenThe length of the bad data is written to this pointer, if not NULL.
Returns
GS1_LINTER_OK if okay.
GS1_LINTER_COUPON_MISSING_GCP_VLI if the data is missing a primary GCP VLI.
GS1_LINTER_COUPON_INVALID_GCP_LENGTH if the data contains a primary GCP with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_GCP if the data contains a primary GCP that is shorter than is indicated by its VLI.
GS1_LINTER_COUPON_MISSING_SAVE_VALUE_VLI if the data is missing a Save Value VLI.
GS1_LINTER_COUPON_INVALID_SAVE_VALUE_LENGTH if the data contains a Save Value VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_SAVE_VALUE if the data comtains a Save Value that is shorter than is indicated by its VLI.
GS1_LINTER_COUPON_MISSING_1ST_PURCHASE_REQUIREMENT_VLI if the data is missing a primary purchace Requirement VLI.
GS1_LINTER_COUPON_INVALID_1ST_PURCHASE_REQUIREMENT_LENGTH if the data contains a primary purchase Requirement VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_1ST_PURCHASE_REQUIREMENT if the data comtains a primary purchase Requirement that is shorter than is indicated by its VLI.
GS1_LINTER_COUPON_MISSING_1ST_PURCHASE_REQUIREMENT_CODE if the data is missing a primary purchase Requirement Code.
GS1_LINTER_COUPON_INVALID_1ST_PURCHASE_REQUIREMENT_CODE if the data contains a primary purchase Requirement Code that is too short.
GS1_LINTER_COUPON_TRUNCATED_1ST_PURCHASE_FAMILY_CODE if the data contains a primary purchase Family Code that is too short.
GS1_LINTER_COUPON_MISSING_ADDITIONAL_PURCHASE_RULES_CODE if the data contains an optional field 1 that is missing an Additional Purchase Rules Code.
GS1_LINTER_COUPON_INVALID_ADDITIONAL_PURCHASE_RULES_CODE if the data contains an optional field 1 whose Additional Purchase Rules Code is invalid.
GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_REQUIREMENT_VLI if the data contains an optional field 1 that is missing a second purchase Requirement VLI.
GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_REQUIREMENT_LENGTH if the data contains an optional field 1 with a second purchase Requirement VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_2ND_PURCHASE_REQUIREMENT if the data contains an optional field 1 whose second purchase Requirement Code is shorter than is indicated by its VLI.
GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_REQUIREMENT_CODE if the data contains an optional field 1 that is missing a second purchase Requirement Code.
GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_REQUIREMENT_CODE if the data contains an optional field 1 whose second purchase Requirement Code is invalid.
GS1_LINTER_COUPON_TRUNCATED_2ND_PURCHASE_FAMILY_CODE if the data contains an optional field 1 whose second purchase Family Code is too short.
GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_GCP_VLI if the data contains an optional field 1 that is missing a second purchase GCP VLI.
GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_GCP_LENGTH if the data contains an optional field 1 with a second purchase GCP VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_2ND_PURCHASE_GCP if the data contains an optional field 1 with a second purchase GCP that is shorter than indicated by its VLI.
GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_REQUIREMENT_VLI if the data contains an optional field 2 that is missing a third purchase Requirement VLI.
GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_REQUIREMENT_LENGTH if the data contains an optional field 2 with a third purchase Requirement VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_3RD_PURCHASE_REQUIREMENT if the data contains an optional field 2 whose third purchase Requirement Code is shorter than is indicated by its VLI.
GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_REQUIREMENT_CODE if the data contains an optional field 2 that is missing a third purchase Requirement Code.
GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_REQUIREMENT_CODE if the data contains an optional field 2 whose third purchase Requirement Code is invalid.
GS1_LINTER_COUPON_TRUNCATED_3RD_PURCHASE_FAMILY_CODE if the data contains an optional field 2 whose third purchase Family Code is too short.
GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_GCP_VLI if the data contains an optional field 2 that is missing a third purchase GCP VLI.
GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_GCP_LENGTH if the data contains an optional field 2 with a third purchase GCP VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_3RD_PURCHASE_GCP if the data contains an optional field 2 with a third purchase GCP that is shorter than indicated by its VLI.
GS1_LINTER_COUPON_TOO_SHORT_FOR_EXPIRATION_DATE if the data contains an optional field 3 whose expiration date is too short.
GS1_LINTER_COUPON_INVALID_EXIPIRATION_DATE if the data contains an optional field 3 whose expiration date is invalid.
GS1_LINTER_COUPON_TOO_SHORT_FOR_START_DATE if the data contains an optional field 4 whose start date is too short.
GS1_LINTER_COUPON_INVALID_START_DATE if the data contains an optional field 4 whose start date is invalid.
GS1_LINTER_COUPON_EXPIRATION_BEFORE_START if the data contains an optional field 3 and an optional field 4 where the expiration date is prior to the start date.
GS1_LINTER_COUPON_MISSING_SERIAL_NUMBER_VLI if the data contains an optional field 5 that is missing the Serial Number VLI.
GS1_LINTER_COUPON_TRUNCATED_SERIAL_NUMBER if the data contains an optional field 5 whose Serial Number is shorter than indicated by its VLI.
GS1_LINTER_COUPON_MISSING_RETAILER_GCP_OR_GLN_VLI f the data contains an optional field 6 that is missing the Retailer GCP/GLN VLI.
GS1_LINTER_COUPON_INVALID_RETAILER_GCP_OR_GLN_LENGTH if the data contains an optional field 6 with a Retailer GCP/GLN VLI with an invalid length.
GS1_LINTER_COUPON_TRUNCATED_RETAILER_GCP_OR_GLN if the data contains an optional field 6 whose Retailer GCP/GLN is shorter than indicated by its VLI.
GS1_LINTER_COUPON_MISSING_SAVE_VALUE_CODE if the data contains an optional field 9 that is missing the Save Value Code.
GS1_LINTER_COUPON_INVALID_SAVE_VALUE_CODE if the data contains an optional field 9 whose Save Value Code is invalid.
GS1_LINTER_COUPON_MISSING_SAVE_VALUE_APPLIES_TO_ITEM if the data contains an optional field 9 that is missing the Save Value Applies to Item value.
GS1_LINTER_COUPON_INVALID_SAVE_VALUE_APPLIES_TO_ITEM if the data contains an optional field 9 whose Save Value Applies to Item value is invalid.
GS1_LINTER_COUPON_MISSING_STORE_COUPON_FLAG if the data contains an optional field 9 that is missing the Store Coupon Flag.
GS1_LINTER_COUPON_MISSING_DONT_MULTIPLY_FLAG if the data contains an optional field 9 that is missing the Don't Multiply Flag.
GS1_LINTER_COUPON_INVALID_DONT_MULTIPLY_FLAG if the data contains an optional field 9 whose Don't Multiply Flag is invalid.
184 {
185 
186  gs1_lint_err_t ret;
187  size_t pos;
188  int vli;
189  const char *p, *q;
190  char expiry_date[7] = {0};
191  int expiry_set = 0;
192  char gcp[14] = {0};
193 
194  assert(data);
195 
196  /*
197  * Data must consist of all digits.
198  *
199  */
200  if ((pos = strspn(data, "0123456789")) != strlen(data)) {
201  if (err_pos) *err_pos = pos;
202  if (err_len) *err_len = 1;
204  }
205 
206  p = data;
207  q = data + strlen(data);
208 
209 
210  /*
211  * Validate that the GCP follows its VLI and has the corresponding
212  * length (plus 6).
213  *
214  * Valid GCP VLIs are "0" to "6".
215  *
216  */
217  if (p == q) {
218  if (err_pos) *err_pos = 0;
219  if (err_len) *err_len = (size_t)(q - data);
221  }
222  if (*p > '6') {
223  if (err_pos) *err_pos = (size_t)(p - data);
224  if (err_len) *err_len = 1;
226  }
227  vli = *p - '0' + 6;
228 
229  p++;
230 
231  if (q - p < vli) {
232  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
233  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
235  }
236 
237  /*
238  * Validate the GCP with the "key" linter.
239  *
240  */
241  strncpy(gcp, p, (size_t)vli);
242  ret = gs1_lint_key(gcp, err_pos, err_len);
243 
244  assert (ret == GS1_LINTER_OK ||
247 
248  if (ret != GS1_LINTER_OK) {
249  if (err_pos) *err_pos = (size_t)(p - data);
250  if (err_len) *err_len = (size_t)vli;
251  return ret;
252  }
253 
254  p += vli;
255 
256 
257  /*
258  * Validate the existence of the six digit Offer Code.
259  *
260  */
261  if (q - p < 6) {
262  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
263  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
265  }
266 
267  p += 6;
268 
269 
270  /*
271  * Validate that the Save Value follows its VLI and has the
272  * corresponding length.
273  *
274  * Valid Save Value VLIs are "1" to "5".
275  *
276  */
277  if (p == q) {
278  if (err_pos) *err_pos = 0;
279  if (err_len) *err_len = (size_t)(q - data);
281  }
282  if (*p < '1' || *p > '5') {
283  if (err_pos) *err_pos = (size_t)(p - data);
284  if (err_len) *err_len = 1;
286  }
287  vli = *p - '0';
288 
289  p++;
290 
291  if (q - p < vli) {
292  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
293  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
295  }
296 
297  p += vli;
298 
299 
300  /*
301  * Validate 1st Purchase Requirement follows its VLI and has the
302  * corresponding length.
303  *
304  * Valid 1st Purchase Requirement VLIs are "1" to "5".
305  *
306  */
307  if (p == q) {
308  if (err_pos) *err_pos = 0;
309  if (err_len) *err_len = (size_t)(q - data);
311  }
312  if (*p < '1' || *p > '5') {
313  if (err_pos) *err_pos = (size_t)(p - data);
314  if (err_len) *err_len = 1;
316  }
317  vli = *p - '0';
318 
319  p++;
320 
321  if (q - p < vli) {
322  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
323  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
325  }
326 
327  p += vli;
328 
329 
330  /*
331  * Validate the single-digit 1st Purchase Requirement Code.
332  *
333  * Valid values for 1st Purchase Requirement Code are "0" to "4" and
334  * "9".
335  *
336  */
337  if (p == q) {
338  if (err_pos) *err_pos = 0;
339  if (err_len) *err_len = (size_t)(q - data);
341  }
342 
343  if (*p > '4' && *p != '9') {
344  if (err_pos) *err_pos = (size_t)(p - data);
345  if (err_len) *err_len = 1;
347  }
348 
349  p++;
350 
351 
352  /*
353  * Validate the existence of the three-digit 1st Purchase Family Code.
354  *
355  */
356  if (q - p < 3) {
357  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
358  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
360  }
361 
362  p += 3;
363 
364 
365  /*
366  * Optional field 1: Additional rules and 2nd purchase
367  * ===================================================
368  *
369  * This option field is indicated by the value "1".
370  *
371  */
372  if (p < q && *p == '1') {
373 
374  p++;
375 
376  /*
377  * Validate the single-digit Additional Purchase Rules Code.
378  *
379  * Valid values for the Additional Purchase Rules Code are "0"
380  * to "3".
381  *
382  */
383  if (p == q) {
384  if (err_pos) *err_pos = 0;
385  if (err_len) *err_len = (size_t)(q - data);
387  }
388 
389  if (*p > '3') {
390  if (err_pos) *err_pos = (size_t)(p - data);
391  if (err_len) *err_len = 1;
393  }
394 
395  p++;
396 
397 
398  /*
399  * Validate 2nd Purchase Requirement follows its VLI and has
400  * the corresponding length.
401  *
402  * Valid values for the 2nd Purchase Requirement VLI are "1" to
403  * "5".
404  *
405  */
406  if (p == q) {
407  if (err_pos) *err_pos = 0;
408  if (err_len) *err_len = (size_t)(q - data);
410  }
411  if (*p < '1' || *p > '5') {
412  if (err_pos) *err_pos = (size_t)(p - data);
413  if (err_len) *err_len = 1;
415  }
416  vli = *p - '0';
417 
418  p++;
419 
420  if (q - p < vli) {
421  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
422  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
424  }
425 
426  p += vli;
427 
428 
429  /*
430  * Validate the single-digit 2nd Purchase Requirement Code.
431  *
432  * Valid values for the 2nd Purchase Requirement Code are "0"
433  * to "4" and "9".
434  *
435  */
436  if (p == q) {
437  if (err_pos) *err_pos = 0;
438  if (err_len) *err_len = (size_t)(q - data);
440  }
441 
442  if (*p > '4' && *p != '9') {
443  if (err_pos) *err_pos = (size_t)(p - data);
444  if (err_len) *err_len = 1;
446  }
447 
448  p++;
449 
450 
451  /*
452  * Validate the existence of the three-digit 2nd Purchase
453  * Family Code.
454  *
455  */
456  if (q - p < 3) {
457  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
458  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
460  }
461 
462  p += 3;
463 
464 
465  /*
466  * Validate that the 2nd Purchase GCP follows its VLI and has
467  * the corresponding length (plus 6, unless VLI is "9").
468  *
469  * Valid values for the 2nd Purchase GCP VLI are "0" to "6" and
470  * "9".
471  *
472  */
473  if (p == q) {
474  if (err_pos) *err_pos = 0;
475  if (err_len) *err_len = (size_t)(q - data);
477  }
478  if (*p > '6' && *p != '9') {
479  if (err_pos) *err_pos = (size_t)(p - data);
480  if (err_len) *err_len = 1;
482  }
483  vli = (*p != '9') ? *p - '0' + 6 : 0;
484 
485  p++;
486 
487  if (q - p < vli) {
488  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
489  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
491  }
492 
493  /*
494  * Validate the GCP with the "key" linter.
495  *
496  */
497  strncpy(gcp, p, (size_t)vli);
498  ret = gs1_lint_key(gcp, err_pos, err_len);
499 
500  assert (ret == GS1_LINTER_OK ||
503 
504  if (ret != GS1_LINTER_OK) {
505  if (err_pos) *err_pos = (size_t)(p - data);
506  if (err_len) *err_len = (size_t)vli;
507  return ret;
508  }
509 
510  p += vli;
511 
512  }
513 
514 
515  /*
516  * Optional field 2: 3rd purchase
517  * ==============================
518  *
519  * This option field is indicated by the value "2".
520  *
521  */
522  if (p < q && *p == '2') {
523 
524  p++;
525 
526  /*
527  * Validate 3rd Purchase Requirement follows its VLI and has
528  * the corresponding length.
529  *
530  * Valid values for the 3rd Purchase Requirement VLI are "1" to
531  * "5".
532  *
533  */
534  if (p == q) {
535  if (err_pos) *err_pos = 0;
536  if (err_len) *err_len = (size_t)(q - data);
538  }
539  if (*p < '1' || *p > '5') {
540  if (err_pos) *err_pos = (size_t)(p - data);
541  if (err_len) *err_len = 1;
543  }
544  vli = *p - '0';
545 
546  p++;
547 
548  if (q - p < vli) {
549  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
550  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
552  }
553 
554  p += vli;
555 
556 
557  /*
558  * Validate the single-digit 3nd Purchase Requirement Code.
559  *
560  * Valie values for the 3nd Purchase Requirement Code are "0"
561  * to "4" and "9".
562  *
563  */
564  if (p == q) {
565  if (err_pos) *err_pos = 0;
566  if (err_len) *err_len = (size_t)(q - data);
568  }
569 
570  if (*p > '4' && *p != '9') {
571  if (err_pos) *err_pos = (size_t)(p - data);
572  if (err_len) *err_len = 1;
574  }
575 
576  p++;
577 
578 
579  /*
580  * Validate that existence of the three digit 3rd Purchase
581  * Family Code.
582  *
583  */
584  if (q - p < 3) {
585  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
586  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
588  }
589 
590  p += 3;
591 
592 
593  /*
594  * Validate that the 3rd Purchase GCP follows its VLI and has
595  * the corresponding length (plus 6, unless VLI is "9").
596  *
597  * Valid values for the 3rd Purchase GCP VLI are "0" to "6" and
598  * "9".
599  *
600  */
601  if (p == q) {
602  if (err_pos) *err_pos = 0;
603  if (err_len) *err_len = (size_t)(q - data);
605  }
606  if (*p > '6' && *p != '9') {
607  if (err_pos) *err_pos = (size_t)(p - data);
608  if (err_len) *err_len = 1;
610  }
611  vli = (*p != '9') ? *p - '0' + 6 : 0;
612 
613  p++;
614 
615  if (q - p < vli) {
616  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
617  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
619  }
620 
621  /*
622  * Validate the GCP with the "key" linter.
623  *
624  */
625  strncpy(gcp, p, (size_t)vli);
626  ret = gs1_lint_key(gcp, err_pos, err_len);
627 
628  assert (ret == GS1_LINTER_OK ||
631 
632  if (ret != GS1_LINTER_OK) {
633  if (err_pos) *err_pos = (size_t)(p - data);
634  if (err_len) *err_len = (size_t)vli;
635  return ret;
636  }
637 
638  p += vli;
639 
640  }
641 
642 
643  /*
644  * Optional field 3: Expiration date
645  * =================================
646  *
647  * This option field is indicated by the value "3".
648  *
649  */
650  if (p < q && *p == '3') {
651 
652  p++;
653 
654  /*
655  * Validate that the expiration date is in YYMMDD format.
656  *
657  */
658  if (q - p < 6) {
659  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
660  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
662  }
663 
664  memcpy(expiry_date, p, 6);
665  ret = gs1_lint_yymmdd(expiry_date, err_pos, err_len);
666 
667  assert(ret == GS1_LINTER_OK ||
668  ret == GS1_LINTER_DATE_TOO_SHORT ||
669  ret == GS1_LINTER_DATE_TOO_LONG ||
671  ret == GS1_LINTER_ILLEGAL_MONTH ||
672  ret == GS1_LINTER_ILLEGAL_DAY);
673 
674  if (ret != GS1_LINTER_OK) {
675  if (err_pos) *err_pos = (size_t)(p - data);
676  if (err_len) *err_len = 6;
678  }
679 
680  p += 6;
681 
682  expiry_set = 1;
683 
684  }
685 
686 
687  /*
688  * Optional field 4: Start date
689  * ============================
690  *
691  * This option field is indicated by the value "4".
692  *
693  */
694  if (p < q && *p == '4') {
695 
696  char start_date[7] = {0};
697 
698  p++;
699 
700  /*
701  * Validate that the start date is in YYMMDD format.
702  *
703  */
704  if (q - p < 6) {
705  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
706  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
708  }
709 
710  memcpy(start_date, p, 6);
711  ret = gs1_lint_yymmdd(start_date, err_pos, err_len);
712 
713  assert(ret == GS1_LINTER_OK ||
714  ret == GS1_LINTER_DATE_TOO_SHORT ||
715  ret == GS1_LINTER_DATE_TOO_LONG ||
717  ret == GS1_LINTER_ILLEGAL_MONTH ||
718  ret == GS1_LINTER_ILLEGAL_DAY);
719 
720  if (ret != GS1_LINTER_OK) {
721  if (err_pos) *err_pos = (size_t)(p - data);
722  if (err_len) *err_len = 6;
724  }
725 
726  /*
727  * If an expiration date has been set, then ensure that it does
728  * not preceed the start date.
729  *
730  */
731  if (expiry_set && strcmp(start_date, expiry_date) > 0) {
732  if (err_pos) *err_pos = (size_t)(p - data - 8);
733  if (err_len) *err_len = 14;
735  }
736 
737  p += 6;
738 
739  }
740 
741 
742  /*
743  * Optional field 5: Serial number
744  * ===============================
745  *
746  * This option field is indicated by the value "5".
747  *
748  */
749  if (p < q && *p == '5') {
750 
751  p++;
752 
753  /*
754  * Validate Serial Number follows its VLI and has the corresponding
755  * length (plus 6).
756  *
757  */
758  if (p == q) {
759  if (err_pos) *err_pos = 0;
760  if (err_len) *err_len = (size_t)(q - data);
762  }
763  vli = *p - '0' + 6;
764 
765  p++;
766 
767  if (q - p < vli) {
768  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
769  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
771  }
772 
773  p += vli;
774 
775  }
776 
777 
778  /*
779  * Optional field 6: Retailer GCP/GLN
780  * ==================================
781  *
782  * This option field is indicated by the value "6".
783  *
784  */
785  if (p < q && *p == '6') {
786 
787  p++;
788 
789  /*
790  * Validate that the Retailer GCP/GLN follows its VLI and has
791  * the corresponding length (plus 6).
792  *
793  * Valid values for the Retailer GCP/GLN VLI are "1" to "7".
794  *
795  */
796  if (p == q) {
797  if (err_pos) *err_pos = 0;
798  if (err_len) *err_len = (size_t)(q - data);
800  }
801  if (*p < '1' || *p > '7') {
802  if (err_pos) *err_pos = (size_t)(p - data);
803  if (err_len) *err_len = 1;
805  }
806  vli = *p - '0' + 6;
807 
808  p++;
809 
810  if (q - p < vli) {
811  if (err_pos) *err_pos = (p == q) ? 0 : (size_t)(p - data);
812  if (err_len) *err_len = (p == q) ? (size_t)(q - data) : (size_t)(q - p);
814  }
815 
816  /*
817  * Validate the GCP/GLN with the "key" linter.
818  *
819  */
820  strncpy(gcp, p, (size_t)vli);
821  ret = gs1_lint_key(gcp, err_pos, err_len);
822 
823  assert (ret == GS1_LINTER_OK ||
826 
827  if (ret != GS1_LINTER_OK) {
828  if (err_pos) *err_pos = (size_t)(p - data);
829  if (err_len) *err_len = (size_t)vli;
830  return ret;
831  }
832 
833  p += vli;
834 
835  }
836 
837 
838  /*
839  * Optional field 9: Miscellaneous
840  * ===============================
841  *
842  * This option field is indicated by the value "9".
843  *
844  */
845  if (p < q && *p == '9') {
846 
847  p++;
848 
849  /*
850  * Validate the single-digit Save Value Code.
851  *
852  * Valid values for the Save Value Code are "0" to "2" and "5"
853  * to "6".
854  *
855  */
856  if (p == q) {
857  if (err_pos) *err_pos = 0;
858  if (err_len) *err_len = (size_t)(q - data);
860  }
861  if (*p != '0' && *p != '1' && *p != '2' && *p != '5' && *p != '6') {
862  if (err_pos) *err_pos = (size_t)(p - data);
863  if (err_len) *err_len = 1;
865  }
866 
867  p++;
868 
869 
870  /*
871  * Validate the single-digit Save Value Applies to Item value.
872  *
873  * Valid values for Save Value Applies to Item are "0" to "2".
874  *
875  */
876  if (p == q) {
877  if (err_pos) *err_pos = 0;
878  if (err_len) *err_len = (size_t)(q - data);
880  }
881  if (*p > '2') {
882  if (err_pos) *err_pos = (size_t)(p - data);
883  if (err_len) *err_len = 1;
885  }
886 
887  p++;
888 
889 
890  /*
891  * Validate the existence of the single-digit Store Coupon
892  * Flag.
893  *
894  */
895  if (p == q) {
896  if (err_pos) *err_pos = 0;
897  if (err_len) *err_len = (size_t)(q - data);
899  }
900 
901  p++;
902 
903 
904  /*
905  * Validate the single-digit Don't Multiply Flag.
906  *
907  * Valid values for the Don't Multiply Flag are "0" and "1".
908  *
909  */
910  if (p == q) {
911  if (err_pos) *err_pos = 0;
912  if (err_len) *err_len = (size_t)(q - data);
914  }
915  if (*p != '0' && *p != '1') {
916  if (err_pos) *err_pos = (size_t)(p - data);
917  if (err_len) *err_len = 1;
919  }
920 
921  p++;
922 
923  }
924 
925  /*
926  * Report excess data that has not been handled as an optional field.
927  *
928  */
929  if (p != q) {
930  if (err_pos) *err_pos = (size_t)(p - data);
931  if (err_len) *err_len = (size_t)(q - p);
933  }
934 
935  return GS1_LINTER_OK;
936 
937 }
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:52
gs1_lint_err_t
Linter return codes other than GS1_LINTER_OK indicate an error condition.
Definition: gs1syntaxdictionary.h:65
@ GS1_LINTER_ILLEGAL_DAY
The date contains an illegal day of the month.
Definition: gs1syntaxdictionary.h:102
@ 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:138
@ 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:158
@ GS1_LINTER_COUPON_INVALID_2ND_PURCHASE_REQUIREMENT_LENGTH
The coupon's second purchase Requirement VLI must be "1" to "5".
Definition: gs1syntaxdictionary.h:134
@ GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_REQUIREMENT_VLI
The coupon's third purchase Requirement VLI is missing.
Definition: gs1syntaxdictionary.h:142
@ GS1_LINTER_COUPON_MISSING_RETAILER_GCP_OR_GLN_VLI
The coupon's Retailer GCP/GLN VLI is missing.
Definition: gs1syntaxdictionary.h:156
@ GS1_LINTER_COUPON_INVALID_3RD_PURCHASE_REQUIREMENT_LENGTH
The coupon's third purchase Requirement VLI must be "1" to "5".
Definition: gs1syntaxdictionary.h:143
@ GS1_LINTER_COUPON_MISSING_1ST_PURCHASE_REQUIREMENT_VLI
The coupon's primary purchase Requirement VLI is missing.
Definition: gs1syntaxdictionary.h:125
@ GS1_LINTER_COUPON_INVALID_SAVE_VALUE_CODE
The coupon's Save Value Code must be "0", "1", "2", "5" or "6".
Definition: gs1syntaxdictionary.h:160
@ 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:140
@ 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:130
@ 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:162
@ GS1_LINTER_COUPON_MISSING_SAVE_VALUE_APPLIES_TO_ITEM
The coupon's Save Value Applies to Item is missing.
Definition: gs1syntaxdictionary.h:161
@ GS1_LINTER_COUPON_TRUNCATED_GCP
The coupon's primary GS1 Company Prefix is shorter than what is indicated by its VLI.
Definition: gs1syntaxdictionary.h:121
@ GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_REQUIREMENT_CODE
The coupon's third purchase Requirement Code is missing.
Definition: gs1syntaxdictionary.h:145
@ 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:144
@ GS1_LINTER_DATE_TOO_LONG
The date is too long for YYMMDD format.
Definition: gs1syntaxdictionary.h:95
@ GS1_LINTER_COUPON_TRUNCATED_SAVE_VALUE
The coupon's Save Value is shorter than what is indicated by its VLI.
Definition: gs1syntaxdictionary.h:124
@ 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:137
@ GS1_LINTER_GCP_DATASOURCE_OFFLINE
The data source for GCP lookups is offline.
Definition: gs1syntaxdictionary.h:76
@ GS1_LINTER_COUPON_MISSING_SERIAL_NUMBER_VLI
The coupon's Serial Number VLI is missing.
Definition: gs1syntaxdictionary.h:117
@ 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:127
@ GS1_LINTER_COUPON_MISSING_1ST_PURCHASE_REQUIREMENT_CODE
The coupon's primary purchase Requirement Code is missing.
Definition: gs1syntaxdictionary.h:128
@ GS1_LINTER_ILLEGAL_MONTH
The date contains an illegal month of the year.
Definition: gs1syntaxdictionary.h:101
@ GS1_LINTER_COUPON_MISSING_GCP_VLI
The coupon's primary GS1 Company Prefix VLI is missing.
Definition: gs1syntaxdictionary.h:119
@ GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_REQUIREMENT_CODE
The coupon's second purchase Requirement Code is missing.
Definition: gs1syntaxdictionary.h:136
@ GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_REQUIREMENT_VLI
The coupon's second purchase Requirement VLI is missing.
Definition: gs1syntaxdictionary.h:133
@ 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:147
@ GS1_LINTER_COUPON_TRUNCATED_SERIAL_NUMBER
The coupon's Serial Number is shorter than what is indicated by its VLI.
Definition: gs1syntaxdictionary.h:118
@ GS1_LINTER_COUPON_TOO_SHORT_FOR_START_DATE
The coupon's start date is too short to YYMMDD format.
Definition: gs1syntaxdictionary.h:153
@ GS1_LINTER_COUPON_INVALID_START_DATE
The coupon's start date is invalid.
Definition: gs1syntaxdictionary.h:154
@ GS1_LINTER_COUPON_INVALID_SAVE_VALUE_LENGTH
The coupon's Save Value VLI must be "1" to "5".
Definition: gs1syntaxdictionary.h:123
@ GS1_LINTER_COUPON_TRUNCATED_OFFER_CODE
The coupon's Offer Code is shorter than the required six digits.
Definition: gs1syntaxdictionary.h:116
@ GS1_LINTER_COUPON_MISSING_ADDITIONAL_PURCHASE_RULES_CODE
The coupon's Additional Purchase Rules Code is missing.
Definition: gs1syntaxdictionary.h:131
@ GS1_LINTER_COUPON_INVALID_DONT_MULTIPLY_FLAG
The coupon's Don't Multiply Flag must be "0" or "1".
Definition: gs1syntaxdictionary.h:165
@ 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:141
@ GS1_LINTER_COUPON_MISSING_STORE_COUPON_FLAG
The coupon's Store Coupon Flag is missing.
Definition: gs1syntaxdictionary.h:163
@ GS1_LINTER_COUPON_EXCESS_DATA
The coupon contains excess data after the recognised optional fields.
Definition: gs1syntaxdictionary.h:166
@ GS1_LINTER_COUPON_MISSING_3RD_PURCHASE_GCP_VLI
The coupon's third purchase GS1 Company Prefix VLI is missing.
Definition: gs1syntaxdictionary.h:148
@ GS1_LINTER_COUPON_MISSING_2ND_PURCHASE_GCP_VLI
The coupon's second purchase GS1 Company Prefix VLI is missing.
Definition: gs1syntaxdictionary.h:139
@ GS1_LINTER_COUPON_TOO_SHORT_FOR_EXPIRATION_DATE
The coupon's expiration date is too short for YYMMDD format.
Definition: gs1syntaxdictionary.h:151
@ GS1_LINTER_COUPON_INVALID_GCP_LENGTH
The coupon's primary GS1 Company Prefix VLI must be "0" to "6".
Definition: gs1syntaxdictionary.h:120
@ GS1_LINTER_DATE_TOO_SHORT
The date is too short for YYMMDD format.
Definition: gs1syntaxdictionary.h:94
@ GS1_LINTER_COUPON_INVALID_EXIPIRATION_DATE
The coupon's expiration date is invalid.
Definition: gs1syntaxdictionary.h:152
@ GS1_LINTER_COUPON_MISSING_SAVE_VALUE_VLI
The coupon's Save Value VLI is missing.
Definition: gs1syntaxdictionary.h:122
@ 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:129
@ 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:135
@ GS1_LINTER_OK
No issues were detected by the linter.
Definition: gs1syntaxdictionary.h:66
@ 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:146
@ GS1_LINTER_COUPON_EXPIRATION_BEFORE_START
The coupon's expiration date preceed the start date.
Definition: gs1syntaxdictionary.h:155
@ GS1_LINTER_COUPON_INVALID_ADDITIONAL_PURCHASE_RULES_CODE
The coupon's Additional Purchase Rules Code must be "0" to "3".
Definition: gs1syntaxdictionary.h:132
@ GS1_LINTER_COUPON_INVALID_1ST_PURCHASE_REQUIREMENT_LENGTH
The coupon's primary purchase Requirement VLI must be "1" to "5".
Definition: gs1syntaxdictionary.h:126
@ GS1_LINTER_INVALID_GCP_PREFIX
The GS1 Company Prefix is invalid.
Definition: gs1syntaxdictionary.h:78
@ 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:150
@ GS1_LINTER_NON_DIGIT_CHARACTER
A non-digit character was found where a digit is expected.
Definition: gs1syntaxdictionary.h:67
@ GS1_LINTER_COUPON_MISSING_DONT_MULTIPLY_FLAG
The coupon's Don't Multiply Flag is missing.
Definition: gs1syntaxdictionary.h:164
@ GS1_LINTER_COUPON_MISSING_SAVE_VALUE_CODE
The coupon's Save Value Code is missing.
Definition: gs1syntaxdictionary.h:159
@ GS1_LINTER_COUPON_INVALID_RETAILER_GCP_OR_GLN_LENGTH
The coupon's Retailer GCP/GLN VLI must be "1" to "7".
Definition: gs1syntaxdictionary.h:157
@ 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:149
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:95