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

Purpose

The yymmd0 linter ensures that the data represents a meaningful date, in YYMMDD format, additionally permitting YYMM00 format indicating an unspecified day.

Macros

#define CURRENT_YEAR   21
 20YY: For converting YY to 19YY, 20YY, 21YY, etc. for leap year validation
 

Functional Description

◆ gs1_lint_yymmd0()

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

Used to ensure that an AI component conforms to the YYMMDD or YYMM00 formats.

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_DATE_TOO_SHORT if the data is too short for YYMMDD format.
GS1_LINTER_DATE_TOO_LONG if the data is too long for YYMMDD format.
GS1_LINTER_NON_DIGIT_CHARACTER if the data contains a non-digit character.
GS1_LINTER_ILLEGAL_MONTH if the data contains an invalid month.
GS1_LINTER_ILLEGAL_DAY if the data contains an invalid day of the month.
61 {
62 
63 /// \cond
64 #define XX(d) ( (data[d] - '0') * 10 + (data[d+1] - '0') )
65 #define YY XX(0)
66 #define MM XX(2)
67 #define DD XX(4)
68 /// \endcond
69 
70  static const int daysinmonth[] =
71  { 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
72 
73  size_t len, pos;
74  int yyyy, maxdd;
75 
76  assert(data);
77 
78  len = strlen(data);
79 
80  /*
81  * Data must be six characters.
82  *
83  */
84  if (len != 6) {
85  if (err_pos) *err_pos = 0;
86  if (err_len) *err_len = len;
88  }
89 
90  /*
91  * Data must consist of all digits.
92  *
93  */
94  if ((pos = strspn(data, "0123456789")) != len) {
95  if (err_pos) *err_pos = pos;
96  if (err_len) *err_len = 1;
98  }
99 
100  /*
101  * Validate that the month is 01 to 12.
102  *
103  */
104  if (MM < 1 || MM > 12) {
105  if (err_pos) *err_pos = 2;
106  if (err_len) *err_len = 2;
108  }
109 
110  /*
111  * Convert YY to a year using a horizon based on CURRENT_YEAR.
112  *
113  */
114  if (YY - CURRENT_YEAR >= 51)
115  yyyy = 1900 + YY;
116  else if (YY - CURRENT_YEAR > -50)
117  yyyy = 2000 + YY;
118  else
119  yyyy = 2100 + YY;
120 
121  /*
122  * Validate the day, accounting for leap years, and permitting "00".
123  *
124  */
125  maxdd = daysinmonth[MM - 1]; /* Based at 0 */
126  if (maxdd == -1) /* February; account for leap years */
127  maxdd = ((yyyy % 4 == 0 && yyyy % 100 != 0) ||
128  yyyy % 400 == 0) ? 29 : 28;
129 
130  if (DD > maxdd) {
131  if (err_pos) *err_pos = 4;
132  if (err_len) *err_len = 2;
133  return GS1_LINTER_ILLEGAL_DAY;
134  }
135 
136  return GS1_LINTER_OK;
137 
138 }
@ GS1_LINTER_ILLEGAL_DAY
The date contains an illegal day of the month.
Definition: gs1syntaxdictionary.h:102
@ GS1_LINTER_DATE_TOO_LONG
The date is too long for YYMMDD format.
Definition: gs1syntaxdictionary.h:95
@ GS1_LINTER_ILLEGAL_MONTH
The date contains an illegal month of the year.
Definition: gs1syntaxdictionary.h:101
@ GS1_LINTER_DATE_TOO_SHORT
The date is too short for YYMMDD format.
Definition: gs1syntaxdictionary.h:94
@ GS1_LINTER_OK
No issues were detected by the linter.
Definition: gs1syntaxdictionary.h:66
@ GS1_LINTER_NON_DIGIT_CHARACTER
A non-digit character was found where a digit is expected.
Definition: gs1syntaxdictionary.h:67
#define CURRENT_YEAR
20YY: For converting YY to 19YY, 20YY, 21YY, etc. for leap year validation
Definition: lint_yymmd0.c:37