PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
isn.c File Reference
#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
#include "isn.h"
#include "EAN13.h"
#include "ISBN.h"
#include "ISMN.h"
#include "ISSN.h"
#include "UPC.h"
Include dependency graph for isn.c:

Go to the source code of this file.

Macros

#define MAXEAN13LEN   18
 

Enumerations

enum  isn_type {
  INVALID, ANY, EAN13, ISBN,
  ISMN, ISSN, UPC
}
 

Functions

static unsigned dehyphenate (char *bufO, char *bufI)
 
static unsigned hyphenate (char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
 
static unsigned weight_checkdig (char *isn, unsigned size)
 
static unsigned checkdig (char *num, unsigned size)
 
static bool ean2isn (ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
 
static void ean2ISBN (char *isn)
 
static void ean2ISMN (char *isn)
 
static void ean2ISSN (char *isn)
 
static void ean2UPC (char *isn)
 
static ean13 str2ean (const char *num)
 
static bool ean2string (ean13 ean, bool errorOK, char *result, bool shortType)
 
static bool string2ean (const char *str, bool errorOK, ean13 *result, enum isn_type accept)
 
void initialize (void)
 
 PG_FUNCTION_INFO_V1 (isn_out)
 
Datum isn_out (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ean13_out)
 
Datum ean13_out (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ean13_in)
 
Datum ean13_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (isbn_in)
 
Datum isbn_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ismn_in)
 
Datum ismn_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (issn_in)
 
Datum issn_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (upc_in)
 
Datum upc_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (isbn_cast_from_ean13)
 
Datum isbn_cast_from_ean13 (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ismn_cast_from_ean13)
 
Datum ismn_cast_from_ean13 (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (issn_cast_from_ean13)
 
Datum issn_cast_from_ean13 (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (upc_cast_from_ean13)
 
Datum upc_cast_from_ean13 (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (is_valid)
 
Datum is_valid (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (make_valid)
 
Datum make_valid (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (accept_weak_input)
 
Datum accept_weak_input (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (weak_input_status)
 
Datum weak_input_status (PG_FUNCTION_ARGS)
 

Variables

 PG_MODULE_MAGIC
 
static const char *const isn_names [] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"}
 
static bool g_weak = false
 
static bool g_initialized = false
 

Macro Definition Documentation

#define MAXEAN13LEN   18

Definition at line 29 of file isn.c.

Referenced by ean13_out(), ean2isn(), ean2string(), and isn_out().

Enumeration Type Documentation

enum isn_type
Enumerator
INVALID 
ANY 
EAN13 
ISBN 
ISMN 
ISSN 
UPC 

Definition at line 31 of file isn.c.

32 {
34 };
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33

Function Documentation

Datum accept_weak_input ( PG_FUNCTION_ARGS  )

Definition at line 1120 of file isn.c.

References g_weak, PG_GETARG_BOOL, and PG_RETURN_BOOL.

1121 {
1122 #ifdef ISN_WEAK_MODE
1123  g_weak = PG_GETARG_BOOL(0);
1124 #else
1125  /* function has no effect */
1126 #endif /* ISN_WEAK_MODE */
1128 }
static bool g_weak
Definition: isn.c:38
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:231
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
static unsigned checkdig ( char *  num,
unsigned  size 
)
static

Definition at line 302 of file isn.c.

Referenced by string2ean().

303 {
304  unsigned check = 0,
305  check3 = 0;
306  unsigned pos = 0;
307 
308  if (*num == 'M')
309  { /* ISMN start with 'M' */
310  check3 = 3;
311  pos = 1;
312  }
313  while (*num && size > 1)
314  {
315  if (isdigit((unsigned char) *num))
316  {
317  if (pos++ % 2)
318  check3 += *num - '0';
319  else
320  check += *num - '0';
321  size--;
322  }
323  num++;
324  }
325  check = (check + 3 * check3) % 10;
326  if (check != 0)
327  check = 10 - check;
328  return check;
329 }
static unsigned dehyphenate ( char *  bufO,
char *  bufI 
)
static

Definition at line 141 of file isn.c.

Referenced by ean2UPC().

142 {
143  unsigned ret = 0;
144 
145  while (*bufI)
146  {
147  if (isdigit((unsigned char) *bufI))
148  {
149  *bufO++ = *bufI;
150  ret++;
151  }
152  bufI++;
153  }
154  *bufO = '\0';
155  return ret;
156 }
Datum ean13_in ( PG_FUNCTION_ARGS  )

Definition at line 979 of file isn.c.

References EAN13, PG_GETARG_CSTRING, PG_RETURN_EAN13, result, and string2ean().

980 {
981  const char *str = PG_GETARG_CSTRING(0);
982  ean13 result;
983 
984  (void) string2ean(str, false, &result, EAN13);
985  PG_RETURN_EAN13(result);
986 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:683
Definition: isn.c:33
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:234
Datum ean13_out ( PG_FUNCTION_ARGS  )

Definition at line 963 of file isn.c.

References buf, ean2string(), MAXEAN13LEN, PG_GETARG_EAN13, PG_RETURN_CSTRING, pstrdup(), result, and val.

964 {
966  char *result;
967  char buf[MAXEAN13LEN + 1];
968 
969  (void) ean2string(val, false, buf, false);
970 
971  result = pstrdup(buf);
972  PG_RETURN_CSTRING(result);
973 }
static bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
Definition: isn.c:531
char * pstrdup(const char *in)
Definition: mcxt.c:1077
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static char * buf
Definition: pg_test_fsync.c:65
#define MAXEAN13LEN
Definition: isn.c:29
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:314
long val
Definition: informix.c:689
static void ean2ISBN ( char *  isn)
inlinestatic

Definition at line 441 of file isn.c.

References hyphenate(), NULL, and weight_checkdig().

Referenced by ean2string().

442 {
443  char *aux;
444  unsigned check;
445 
446  /*
447  * The number should come in this format: 978-0-000-00000-0 or may be an
448  * ISBN-13 number, 979-..., which does not have a short representation. Do
449  * the short output version if possible.
450  */
451  if (strncmp("978-", isn, 4) == 0)
452  {
453  /* Strip the first part and calculate the new check digit */
454  hyphenate(isn, isn + 4, NULL, NULL);
455  check = weight_checkdig(isn, 10);
456  aux = strchr(isn, '\0');
457  while (!isdigit((unsigned char) *--aux));
458  if (check == 10)
459  *aux = 'X';
460  else
461  *aux = check + '0';
462  }
463 }
static unsigned weight_checkdig(char *isn, unsigned size)
Definition: isn.c:276
#define NULL
Definition: c.h:229
static unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
Definition: isn.c:166
static void ean2ISMN ( char *  isn)
inlinestatic

Definition at line 466 of file isn.c.

References hyphenate(), and NULL.

Referenced by ean2string().

467 {
468  /* the number should come in this format: 979-0-000-00000-0 */
469  /* Just strip the first part and change the first digit ('0') to 'M' */
470  hyphenate(isn, isn + 4, NULL, NULL);
471  isn[0] = 'M';
472 }
#define NULL
Definition: c.h:229
static unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
Definition: isn.c:166
static bool ean2isn ( ean13  ean,
bool  errorOK,
ean13 result,
enum isn_type  accept 
)
static

Definition at line 339 of file isn.c.

References ANY, buf, EAN13, EAN13_FORMAT, ereport, errcode(), errmsg(), ERROR, INVALID, ISBN, ISMN, isn_names, ISSN, MAXEAN13LEN, snprintf(), NODE::type, UINT64CONST, and UPC.

Referenced by isbn_cast_from_ean13(), ismn_cast_from_ean13(), issn_cast_from_ean13(), and upc_cast_from_ean13().

340 {
341  enum isn_type type = INVALID;
342 
343  char buf[MAXEAN13LEN + 1];
344  char *aux;
345  unsigned digval;
346  unsigned search;
347  ean13 ret = ean;
348 
349  ean >>= 1;
350  /* verify it's in the EAN13 range */
351  if (ean > UINT64CONST(9999999999999))
352  goto eantoobig;
353 
354  /* convert the number */
355  search = 0;
356  aux = buf + 13;
357  *aux = '\0'; /* terminate string; aux points to last digit */
358  do
359  {
360  digval = (unsigned) (ean % 10); /* get the decimal value */
361  ean /= 10; /* get next digit */
362  *--aux = (char) (digval + '0'); /* convert to ascii and store */
363  } while (ean && search++ < 12);
364  while (search++ < 12)
365  *--aux = '0'; /* fill the remaining EAN13 with '0' */
366 
367  /* find out the data type: */
368  if (strncmp("978", buf, 3) == 0)
369  { /* ISBN */
370  type = ISBN;
371  }
372  else if (strncmp("977", buf, 3) == 0)
373  { /* ISSN */
374  type = ISSN;
375  }
376  else if (strncmp("9790", buf, 4) == 0)
377  { /* ISMN */
378  type = ISMN;
379  }
380  else if (strncmp("979", buf, 3) == 0)
381  { /* ISBN-13 */
382  type = ISBN;
383  }
384  else if (*buf == '0')
385  { /* UPC */
386  type = UPC;
387  }
388  else
389  {
390  type = EAN13;
391  }
392  if (accept != ANY && accept != EAN13 && accept != type)
393  goto eanwrongtype;
394 
395  *result = ret;
396  return true;
397 
398 eanwrongtype:
399  if (!errorOK)
400  {
401  if (type != EAN13)
402  {
403  ereport(ERROR,
404  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
405  errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",
406  isn_names[type], isn_names[accept], buf)));
407  }
408  else
409  {
410  ereport(ERROR,
411  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
412  errmsg("cannot cast %s to %s for number: \"%s\"",
413  isn_names[type], isn_names[accept], buf)));
414  }
415  }
416  return false;
417 
418 eantoobig:
419  if (!errorOK)
420  {
421  char eanbuf[64];
422 
423  /*
424  * Format the number separately to keep the machine-dependent format
425  * code out of the translatable message text
426  */
427  snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
428  ereport(ERROR,
429  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
430  errmsg("value \"%s\" is out of range for %s type",
431  eanbuf, isn_names[type])));
432  }
433  return false;
434 }
#define accept(s, addr, addrlen)
Definition: win32.h:382
Definition: isn.c:33
Definition: isn.c:33
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: isn.c:33
return result
Definition: formatting.c:1618
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
isn_type
Definition: isn.c:31
#define EAN13_FORMAT
Definition: isn.h:28
#define ERROR
Definition: elog.h:43
uint64 ean13
Definition: isn.h:26
static char * buf
Definition: pg_test_fsync.c:65
Definition: isn.c:33
#define ereport(elevel, rest)
Definition: elog.h:122
#define MAXEAN13LEN
Definition: isn.c:29
static const char *const isn_names[]
Definition: isn.c:36
#define UINT64CONST(x)
Definition: c.h:311
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void ean2ISSN ( char *  isn)
inlinestatic

Definition at line 475 of file isn.c.

References hyphenate(), NULL, and weight_checkdig().

Referenced by ean2string().

476 {
477  unsigned check;
478 
479  /* the number should come in this format: 977-0000-000-00-0 */
480  /* Strip the first part, crop, and calculate the new check digit */
481  hyphenate(isn, isn + 4, NULL, NULL);
482  check = weight_checkdig(isn, 8);
483  if (check == 10)
484  isn[8] = 'X';
485  else
486  isn[8] = check + '0';
487  isn[9] = '\0';
488 }
static unsigned weight_checkdig(char *isn, unsigned size)
Definition: isn.c:276
#define NULL
Definition: c.h:229
static unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
Definition: isn.c:166
static bool ean2string ( ean13  ean,
bool  errorOK,
char *  result,
bool  shortType 
)
static

Definition at line 531 of file isn.c.

References EAN13, EAN13_FORMAT, EAN13_index, EAN13_range, ean2ISBN(), ean2ISMN(), ean2ISSN(), ean2UPC(), ereport, errcode(), errmsg(), ERROR, hyphenate(), INVALID, ISBN, ISBN_index, ISBN_index_new, ISBN_range, ISBN_range_new, ISMN, ISMN_index, ISMN_range, isn_names, ISSN, ISSN_index, ISSN_range, MAXEAN13LEN, NULL, snprintf(), NODE::type, UINT64CONST, UPC, UPC_index, and UPC_range.

Referenced by ean13_out(), and isn_out().

532 {
533  const char *(*TABLE)[2];
534  const unsigned (*TABLE_index)[2];
535  enum isn_type type = INVALID;
536 
537  char *aux;
538  unsigned digval;
539  unsigned search;
540  char valid = '\0'; /* was the number initially written with a
541  * valid check digit? */
542 
543  TABLE_index = ISBN_index;
544 
545  if ((ean & 1) != 0)
546  valid = '!';
547  ean >>= 1;
548  /* verify it's in the EAN13 range */
549  if (ean > UINT64CONST(9999999999999))
550  goto eantoobig;
551 
552  /* convert the number */
553  search = 0;
554  aux = result + MAXEAN13LEN;
555  *aux = '\0'; /* terminate string; aux points to last digit */
556  *--aux = valid; /* append '!' for numbers with invalid but
557  * corrected check digit */
558  do
559  {
560  digval = (unsigned) (ean % 10); /* get the decimal value */
561  ean /= 10; /* get next digit */
562  *--aux = (char) (digval + '0'); /* convert to ascii and store */
563  if (search == 0)
564  *--aux = '-'; /* the check digit is always there */
565  } while (ean && search++ < 13);
566  while (search++ < 13)
567  *--aux = '0'; /* fill the remaining EAN13 with '0' */
568 
569  /* The string should be in this form: ???DDDDDDDDDDDD-D" */
570  search = hyphenate(result, result + 3, EAN13_range, EAN13_index);
571 
572  /* verify it's a logically valid EAN13 */
573  if (search == 0)
574  {
575  search = hyphenate(result, result + 3, NULL, NULL);
576  goto okay;
577  }
578 
579  /* find out what type of hyphenation is needed: */
580  if (strncmp("978-", result, search) == 0)
581  { /* ISBN -13 978-range */
582  /* The string should be in this form: 978-??000000000-0" */
583  type = ISBN;
584  TABLE = ISBN_range;
585  TABLE_index = ISBN_index;
586  }
587  else if (strncmp("977-", result, search) == 0)
588  { /* ISSN */
589  /* The string should be in this form: 977-??000000000-0" */
590  type = ISSN;
591  TABLE = ISSN_range;
592  TABLE_index = ISSN_index;
593  }
594  else if (strncmp("979-0", result, search + 1) == 0)
595  { /* ISMN */
596  /* The string should be in this form: 979-0?000000000-0" */
597  type = ISMN;
598  TABLE = ISMN_range;
599  TABLE_index = ISMN_index;
600  }
601  else if (strncmp("979-", result, search) == 0)
602  { /* ISBN-13 979-range */
603  /* The string should be in this form: 979-??000000000-0" */
604  type = ISBN;
605  TABLE = ISBN_range_new;
606  TABLE_index = ISBN_index_new;
607  }
608  else if (*result == '0')
609  { /* UPC */
610  /* The string should be in this form: 000-00000000000-0" */
611  type = UPC;
612  TABLE = UPC_range;
613  TABLE_index = UPC_index;
614  }
615  else
616  {
617  type = EAN13;
618  TABLE = NULL;
619  TABLE_index = NULL;
620  }
621 
622  /* verify it's a logically valid EAN13/UPC/ISxN */
623  digval = search;
624  search = hyphenate(result + digval, result + digval + 2, TABLE, TABLE_index);
625 
626  /* verify it's a valid EAN13 */
627  if (search == 0)
628  {
629  search = hyphenate(result + digval, result + digval + 2, NULL, NULL);
630  goto okay;
631  }
632 
633 okay:
634  /* convert to the old short type: */
635  if (shortType)
636  switch (type)
637  {
638  case ISBN:
639  ean2ISBN(result);
640  break;
641  case ISMN:
642  ean2ISMN(result);
643  break;
644  case ISSN:
645  ean2ISSN(result);
646  break;
647  case UPC:
648  ean2UPC(result);
649  break;
650  default:
651  break;
652  }
653  return true;
654 
655 eantoobig:
656  if (!errorOK)
657  {
658  char eanbuf[64];
659 
660  /*
661  * Format the number separately to keep the machine-dependent format
662  * code out of the translatable message text
663  */
664  snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
665  ereport(ERROR,
666  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
667  errmsg("value \"%s\" is out of range for %s type",
668  eanbuf, isn_names[type])));
669  }
670  return false;
671 }
const char * ISBN_range_new[][2]
Definition: ISBN.h:983
Definition: isn.c:33
const unsigned UPC_index[10][2]
Definition: UPC.h:14
const unsigned ISSN_index[10][2]
Definition: ISSN.h:34
Definition: isn.c:33
static void ean2ISBN(char *isn)
Definition: isn.c:441
static void ean2UPC(char *isn)
Definition: isn.c:491
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: isn.c:33
return result
Definition: formatting.c:1618
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
isn_type
Definition: isn.c:31
const unsigned EAN13_index[10][2]
Definition: EAN13.h:14
#define EAN13_FORMAT
Definition: isn.h:28
#define ERROR
Definition: elog.h:43
const unsigned ISMN_index[10][2]
Definition: ISMN.h:33
const char * EAN13_range[][2]
Definition: EAN13.h:26
const unsigned ISBN_index_new[10][2]
Definition: ISBN.h:970
#define ereport(elevel, rest)
Definition: elog.h:122
#define MAXEAN13LEN
Definition: isn.c:29
static const char *const isn_names[]
Definition: isn.c:36
const char * ISSN_range[][2]
Definition: ISSN.h:46
#define UINT64CONST(x)
Definition: c.h:311
Definition: isn.c:33
Definition: isn.c:33
#define NULL
Definition: c.h:229
static unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
Definition: isn.c:166
static void ean2ISMN(char *isn)
Definition: isn.c:466
const unsigned ISBN_index[10][2]
Definition: ISBN.h:37
const char * ISMN_range[][2]
Definition: ISMN.h:45
Definition: isn.c:33
const char * ISBN_range[][2]
Definition: ISBN.h:50
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void ean2ISSN(char *isn)
Definition: isn.c:475
const char * UPC_range[][2]
Definition: UPC.h:26
static void ean2UPC ( char *  isn)
inlinestatic

Definition at line 491 of file isn.c.

References dehyphenate().

Referenced by ean2string().

492 {
493  /* the number should come in this format: 000-000000000-0 */
494  /* Strip the first part, crop, and dehyphenate */
495  dehyphenate(isn, isn + 1);
496  isn[12] = '\0';
497 }
static unsigned dehyphenate(char *bufO, char *bufI)
Definition: isn.c:141
static unsigned hyphenate ( char *  bufO,
char *  bufI,
const char *(*)  TABLE[2],
const unsigned  TABLE_index[10][2] 
)
static

Definition at line 166 of file isn.c.

References lower(), NULL, and upper().

Referenced by ean2ISBN(), ean2ISMN(), ean2ISSN(), and ean2string().

167 {
168  unsigned ret = 0;
169  const char *ean_aux1,
170  *ean_aux2,
171  *ean_p;
172  char *firstdig,
173  *aux1,
174  *aux2;
175  unsigned search,
176  upper,
177  lower,
178  step;
179  bool ean_in1,
180  ean_in2;
181 
182  /* just compress the string if no further hyphenation is required */
183  if (TABLE == NULL || TABLE_index == NULL)
184  {
185  while (*bufI)
186  {
187  *bufO++ = *bufI++;
188  ret++;
189  }
190  *bufO = '\0';
191  return (ret + 1);
192  }
193 
194  /* add remaining hyphenations */
195 
196  search = *bufI - '0';
197  upper = lower = TABLE_index[search][0];
198  upper += TABLE_index[search][1];
199  lower--;
200 
201  step = (upper - lower) / 2;
202  if (step == 0)
203  return 0;
204  search = lower + step;
205 
206  firstdig = bufI;
207  ean_in1 = ean_in2 = false;
208  ean_aux1 = TABLE[search][0];
209  ean_aux2 = TABLE[search][1];
210  do
211  {
212  if ((ean_in1 || *firstdig >= *ean_aux1) && (ean_in2 || *firstdig <= *ean_aux2))
213  {
214  if (*firstdig > *ean_aux1)
215  ean_in1 = true;
216  if (*firstdig < *ean_aux2)
217  ean_in2 = true;
218  if (ean_in1 && ean_in2)
219  break;
220 
221  firstdig++, ean_aux1++, ean_aux2++;
222  if (!(*ean_aux1 && *ean_aux2 && *firstdig))
223  break;
224  if (!isdigit((unsigned char) *ean_aux1))
225  ean_aux1++, ean_aux2++;
226  }
227  else
228  {
229  /*
230  * check in what direction we should go and move the pointer
231  * accordingly
232  */
233  if (*firstdig < *ean_aux1 && !ean_in1)
234  upper = search;
235  else
236  lower = search;
237 
238  step = (upper - lower) / 2;
239  search = lower + step;
240 
241  /* Initialize stuff again: */
242  firstdig = bufI;
243  ean_in1 = ean_in2 = false;
244  ean_aux1 = TABLE[search][0];
245  ean_aux2 = TABLE[search][1];
246  }
247  } while (step);
248 
249  if (step)
250  {
251  aux1 = bufO;
252  aux2 = bufI;
253  ean_p = TABLE[search][0];
254  while (*ean_p && *aux2)
255  {
256  if (*ean_p++ != '-')
257  *aux1++ = *aux2++;
258  else
259  *aux1++ = '-';
260  ret++;
261  }
262  *aux1++ = '-';
263  *aux1 = *aux2; /* add a lookahead char */
264  return (ret + 1);
265  }
266  return ret;
267 }
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
#define NULL
Definition: c.h:229
void initialize ( void  )

Definition at line 926 of file isn.c.

References EAN13, EAN13_index, elog, g_initialized, ISBN, ISBN_index, ISMN, ISMN_index, ISSN, ISSN_index, LOG, UPC, and UPC_index.

Referenced by gather_merge_init().

927 {
928 #ifdef ISN_DEBUG
929  if (!check_table(EAN13, EAN13_index))
930  elog(LOG, "EAN13 failed check");
931  if (!check_table(ISBN, ISBN_index))
932  elog(LOG, "ISBN failed check");
933  if (!check_table(ISMN, ISMN_index))
934  elog(LOG, "ISMN failed check");
935  if (!check_table(ISSN, ISSN_index))
936  elog(LOG, "ISSN failed check");
937  if (!check_table(UPC, UPC_index))
938  elog(LOG, "UPC failed check");
939 #endif
940  g_initialized = true;
941 }
Definition: isn.c:33
const unsigned UPC_index[10][2]
Definition: UPC.h:14
const unsigned ISSN_index[10][2]
Definition: ISSN.h:34
Definition: isn.c:33
#define LOG
Definition: elog.h:26
const unsigned EAN13_index[10][2]
Definition: EAN13.h:14
static bool g_initialized
Definition: isn.c:39
const unsigned ISMN_index[10][2]
Definition: ISMN.h:33
Definition: isn.c:33
Definition: isn.c:33
const unsigned ISBN_index[10][2]
Definition: ISBN.h:37
Definition: isn.c:33
#define elog
Definition: elog.h:219
Datum is_valid ( PG_FUNCTION_ARGS  )

Definition at line 1095 of file isn.c.

References PG_GETARG_EAN13, PG_RETURN_BOOL, and val.

1096 {
1097  ean13 val = PG_GETARG_EAN13(0);
1098 
1099  PG_RETURN_BOOL((val & 1) == 0);
1100 }
uint64 ean13
Definition: isn.h:26
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
long val
Definition: informix.c:689
Datum isbn_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1044 of file isn.c.

References ean2isn(), ISBN, PG_GETARG_EAN13, PG_RETURN_EAN13, result, and val.

1045 {
1046  ean13 val = PG_GETARG_EAN13(0);
1047  ean13 result;
1048 
1049  (void) ean2isn(val, false, &result, ISBN);
1050 
1051  PG_RETURN_EAN13(result);
1052 }
Definition: isn.c:33
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:339
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
long val
Definition: informix.c:689
Datum isbn_in ( PG_FUNCTION_ARGS  )

Definition at line 992 of file isn.c.

References ISBN, PG_GETARG_CSTRING, PG_RETURN_EAN13, result, and string2ean().

993 {
994  const char *str = PG_GETARG_CSTRING(0);
995  ean13 result;
996 
997  (void) string2ean(str, false, &result, ISBN);
998  PG_RETURN_EAN13(result);
999 }
Definition: isn.c:33
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:683
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:234
Datum ismn_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1056 of file isn.c.

References ean2isn(), ISMN, PG_GETARG_EAN13, PG_RETURN_EAN13, result, and val.

1057 {
1058  ean13 val = PG_GETARG_EAN13(0);
1059  ean13 result;
1060 
1061  (void) ean2isn(val, false, &result, ISMN);
1062 
1063  PG_RETURN_EAN13(result);
1064 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
Definition: isn.c:33
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:339
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
long val
Definition: informix.c:689
Datum ismn_in ( PG_FUNCTION_ARGS  )

Definition at line 1005 of file isn.c.

References ISMN, PG_GETARG_CSTRING, PG_RETURN_EAN13, result, and string2ean().

1006 {
1007  const char *str = PG_GETARG_CSTRING(0);
1008  ean13 result;
1009 
1010  (void) string2ean(str, false, &result, ISMN);
1011  PG_RETURN_EAN13(result);
1012 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
Definition: isn.c:33
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:683
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:234
Datum isn_out ( PG_FUNCTION_ARGS  )

Definition at line 947 of file isn.c.

References buf, ean2string(), MAXEAN13LEN, PG_GETARG_EAN13, PG_RETURN_CSTRING, pstrdup(), result, and val.

948 {
950  char *result;
951  char buf[MAXEAN13LEN + 1];
952 
953  (void) ean2string(val, false, buf, true);
954 
955  result = pstrdup(buf);
956  PG_RETURN_CSTRING(result);
957 }
static bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
Definition: isn.c:531
char * pstrdup(const char *in)
Definition: mcxt.c:1077
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static char * buf
Definition: pg_test_fsync.c:65
#define MAXEAN13LEN
Definition: isn.c:29
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:314
long val
Definition: informix.c:689
Datum issn_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1068 of file isn.c.

References ean2isn(), ISSN, PG_GETARG_EAN13, PG_RETURN_EAN13, result, and val.

1069 {
1070  ean13 val = PG_GETARG_EAN13(0);
1071  ean13 result;
1072 
1073  (void) ean2isn(val, false, &result, ISSN);
1074 
1075  PG_RETURN_EAN13(result);
1076 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:339
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
Definition: isn.c:33
long val
Definition: informix.c:689
Datum issn_in ( PG_FUNCTION_ARGS  )

Definition at line 1018 of file isn.c.

References ISSN, PG_GETARG_CSTRING, PG_RETURN_EAN13, result, and string2ean().

1019 {
1020  const char *str = PG_GETARG_CSTRING(0);
1021  ean13 result;
1022 
1023  (void) string2ean(str, false, &result, ISSN);
1024  PG_RETURN_EAN13(result);
1025 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
Definition: isn.c:33
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:683
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:234
Datum make_valid ( PG_FUNCTION_ARGS  )

Definition at line 1106 of file isn.c.

References PG_GETARG_EAN13, PG_RETURN_EAN13, and val.

1107 {
1108  ean13 val = PG_GETARG_EAN13(0);
1109 
1110  val &= ~((ean13) 1);
1111  PG_RETURN_EAN13(val);
1112 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
long val
Definition: informix.c:689
PG_FUNCTION_INFO_V1 ( isn_out  )
PG_FUNCTION_INFO_V1 ( ean13_out  )
PG_FUNCTION_INFO_V1 ( ean13_in  )
PG_FUNCTION_INFO_V1 ( isbn_in  )
PG_FUNCTION_INFO_V1 ( ismn_in  )
PG_FUNCTION_INFO_V1 ( issn_in  )
PG_FUNCTION_INFO_V1 ( upc_in  )
PG_FUNCTION_INFO_V1 ( isbn_cast_from_ean13  )
PG_FUNCTION_INFO_V1 ( ismn_cast_from_ean13  )
PG_FUNCTION_INFO_V1 ( issn_cast_from_ean13  )
PG_FUNCTION_INFO_V1 ( upc_cast_from_ean13  )
PG_FUNCTION_INFO_V1 ( is_valid  )
PG_FUNCTION_INFO_V1 ( make_valid  )
PG_FUNCTION_INFO_V1 ( accept_weak_input  )
PG_FUNCTION_INFO_V1 ( weak_input_status  )
static ean13 str2ean ( const char *  num)
static

Definition at line 507 of file isn.c.

Referenced by string2ean().

508 {
509  ean13 ean = 0; /* current ean */
510 
511  while (*num)
512  {
513  if (isdigit((unsigned char) *num))
514  ean = 10 * ean + (*num - '0');
515  num++;
516  }
517  return (ean << 1); /* also give room to a flag */
518 }
uint64 ean13
Definition: isn.h:26
static bool string2ean ( const char *  str,
bool  errorOK,
ean13 result,
enum isn_type  accept 
)
static

Definition at line 683 of file isn.c.

References ANY, buf, checkdig(), EAN13, ereport, errcode(), errmsg(), ERROR, g_weak, INVALID, ISBN, ISMN, isn_names, ISSN, length(), str2ean(), NODE::type, UPC, and weight_checkdig().

Referenced by ean13_in(), isbn_in(), ismn_in(), issn_in(), and upc_in().

685 {
686  bool digit,
687  last;
688  char buf[17] = " ";
689  char *aux1 = buf + 3; /* leave space for the first part, in case
690  * it's needed */
691  const char *aux2 = str;
692  enum isn_type type = INVALID;
693  unsigned check = 0,
694  rcheck = (unsigned) -1;
695  unsigned length = 0;
696  bool magic = false,
697  valid = true;
698 
699  /* recognize and validate the number: */
700  while (*aux2 && length <= 13)
701  {
702  last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0'); /* is the last character */
703  digit = (isdigit((unsigned char) *aux2) != 0); /* is current character
704  * a digit? */
705  if (*aux2 == '?' && last) /* automagically calculate check digit
706  * if it's '?' */
707  magic = digit = true;
708  if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))
709  {
710  /* only ISMN can be here */
711  if (type != INVALID)
712  goto eaninvalid;
713  type = ISMN;
714  *aux1++ = 'M';
715  length++;
716  }
717  else if (length == 7 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
718  {
719  /* only ISSN can be here */
720  if (type != INVALID)
721  goto eaninvalid;
722  type = ISSN;
723  *aux1++ = toupper((unsigned char) *aux2);
724  length++;
725  }
726  else if (length == 9 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
727  {
728  /* only ISBN and ISMN can be here */
729  if (type != INVALID && type != ISMN)
730  goto eaninvalid;
731  if (type == INVALID)
732  type = ISBN; /* ISMN must start with 'M' */
733  *aux1++ = toupper((unsigned char) *aux2);
734  length++;
735  }
736  else if (length == 11 && digit && last)
737  {
738  /* only UPC can be here */
739  if (type != INVALID)
740  goto eaninvalid;
741  type = UPC;
742  *aux1++ = *aux2;
743  length++;
744  }
745  else if (*aux2 == '-' || *aux2 == ' ')
746  {
747  /* skip, we could validate but I think it's worthless */
748  }
749  else if (*aux2 == '!' && *(aux2 + 1) == '\0')
750  {
751  /* the invalid check digit suffix was found, set it */
752  if (!magic)
753  valid = false;
754  magic = true;
755  }
756  else if (!digit)
757  {
758  goto eaninvalid;
759  }
760  else
761  {
762  *aux1++ = *aux2;
763  if (++length > 13)
764  goto eantoobig;
765  }
766  aux2++;
767  }
768  *aux1 = '\0'; /* terminate the string */
769 
770  /* find the current check digit value */
771  if (length == 13)
772  {
773  /* only EAN13 can be here */
774  if (type != INVALID)
775  goto eaninvalid;
776  type = EAN13;
777  check = buf[15] - '0';
778  }
779  else if (length == 12)
780  {
781  /* only UPC can be here */
782  if (type != UPC)
783  goto eaninvalid;
784  check = buf[14] - '0';
785  }
786  else if (length == 10)
787  {
788  if (type != ISBN && type != ISMN)
789  goto eaninvalid;
790  if (buf[12] == 'X')
791  check = 10;
792  else
793  check = buf[12] - '0';
794  }
795  else if (length == 8)
796  {
797  if (type != INVALID && type != ISSN)
798  goto eaninvalid;
799  type = ISSN;
800  if (buf[10] == 'X')
801  check = 10;
802  else
803  check = buf[10] - '0';
804  }
805  else
806  goto eaninvalid;
807 
808  if (type == INVALID)
809  goto eaninvalid;
810 
811  /* obtain the real check digit value, validate, and convert to ean13: */
812  if (accept == EAN13 && type != accept)
813  goto eanwrongtype;
814  if (accept != ANY && type != EAN13 && type != accept)
815  goto eanwrongtype;
816  switch (type)
817  {
818  case EAN13:
819  valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));
820  /* now get the subtype of EAN13: */
821  if (buf[3] == '0')
822  type = UPC;
823  else if (strncmp("977", buf + 3, 3) == 0)
824  type = ISSN;
825  else if (strncmp("978", buf + 3, 3) == 0)
826  type = ISBN;
827  else if (strncmp("9790", buf + 3, 4) == 0)
828  type = ISMN;
829  else if (strncmp("979", buf + 3, 3) == 0)
830  type = ISBN;
831  if (accept != EAN13 && accept != ANY && type != accept)
832  goto eanwrongtype;
833  break;
834  case ISMN:
835  memcpy(buf, "9790", 4); /* this isn't for sure yet, for now
836  * ISMN it's only 9790 */
837  valid = (valid && ((rcheck = checkdig(buf, 13)) == check || magic));
838  break;
839  case ISBN:
840  memcpy(buf, "978", 3);
841  valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
842  break;
843  case ISSN:
844  memcpy(buf + 10, "00", 2); /* append 00 as the normal issue
845  * publication code */
846  memcpy(buf, "977", 3);
847  valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));
848  break;
849  case UPC:
850  buf[2] = '0';
851  valid = (valid && ((rcheck = checkdig(buf + 2, 13)) == check || magic));
852  default:
853  break;
854  }
855 
856  /* fix the check digit: */
857  for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
858  aux1[12] = checkdig(aux1, 13) + '0';
859  aux1[13] = '\0';
860 
861  if (!valid && !magic)
862  goto eanbadcheck;
863 
864  *result = str2ean(aux1);
865  *result |= valid ? 0 : 1;
866  return true;
867 
868 eanbadcheck:
869  if (g_weak)
870  { /* weak input mode is activated: */
871  /* set the "invalid-check-digit-on-input" flag */
872  *result = str2ean(aux1);
873  *result |= 1;
874  return true;
875  }
876 
877  if (!errorOK)
878  {
879  if (rcheck == (unsigned) -1)
880  {
881  ereport(ERROR,
882  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
883  errmsg("invalid %s number: \"%s\"",
884  isn_names[accept], str)));
885  }
886  else
887  {
888  ereport(ERROR,
889  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
890  errmsg("invalid check digit for %s number: \"%s\", should be %c",
891  isn_names[accept], str, (rcheck == 10) ? ('X') : (rcheck + '0'))));
892  }
893  }
894  return false;
895 
896 eaninvalid:
897  if (!errorOK)
898  ereport(ERROR,
899  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
900  errmsg("invalid input syntax for %s number: \"%s\"",
901  isn_names[accept], str)));
902  return false;
903 
904 eanwrongtype:
905  if (!errorOK)
906  ereport(ERROR,
907  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
908  errmsg("cannot cast %s to %s for number: \"%s\"",
909  isn_names[type], isn_names[accept], str)));
910  return false;
911 
912 eantoobig:
913  if (!errorOK)
914  ereport(ERROR,
915  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
916  errmsg("value \"%s\" is out of range for %s type",
917  str, isn_names[accept])));
918  return false;
919 }
#define accept(s, addr, addrlen)
Definition: win32.h:382
int length(const List *list)
Definition: list.c:1271
Definition: isn.c:33
Definition: isn.c:33
static bool g_weak
Definition: isn.c:38
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: isn.c:33
return result
Definition: formatting.c:1618
isn_type
Definition: isn.c:31
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:65
static unsigned weight_checkdig(char *isn, unsigned size)
Definition: isn.c:276
Definition: isn.c:33
#define ereport(elevel, rest)
Definition: elog.h:122
static const char *const isn_names[]
Definition: isn.c:36
static unsigned checkdig(char *num, unsigned size)
Definition: isn.c:302
static ean13 str2ean(const char *num)
Definition: isn.c:507
Definition: isn.c:33
Definition: isn.c:33
Definition: isn.c:33
int errmsg(const char *fmt,...)
Definition: elog.c:797
Datum upc_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1080 of file isn.c.

References ean2isn(), PG_GETARG_EAN13, PG_RETURN_EAN13, result, UPC, and val.

1081 {
1082  ean13 val = PG_GETARG_EAN13(0);
1083  ean13 result;
1084 
1085  (void) ean2isn(val, false, &result, UPC);
1086 
1087  PG_RETURN_EAN13(result);
1088 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:339
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
Definition: isn.c:33
long val
Definition: informix.c:689
Datum upc_in ( PG_FUNCTION_ARGS  )

Definition at line 1031 of file isn.c.

References PG_GETARG_CSTRING, PG_RETURN_EAN13, result, string2ean(), and UPC.

1032 {
1033  const char *str = PG_GETARG_CSTRING(0);
1034  ean13 result;
1035 
1036  (void) string2ean(str, false, &result, UPC);
1037  PG_RETURN_EAN13(result);
1038 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
return result
Definition: formatting.c:1618
uint64 ean13
Definition: isn.h:26
Definition: isn.c:33
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:683
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:234
Datum weak_input_status ( PG_FUNCTION_ARGS  )

Definition at line 1132 of file isn.c.

References g_weak, and PG_RETURN_BOOL.

1133 {
1135 }
static bool g_weak
Definition: isn.c:38
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
static unsigned weight_checkdig ( char *  isn,
unsigned  size 
)
static

Definition at line 276 of file isn.c.

Referenced by ean2ISBN(), ean2ISSN(), and string2ean().

277 {
278  unsigned weight = 0;
279 
280  while (*isn && size > 1)
281  {
282  if (isdigit((unsigned char) *isn))
283  {
284  weight += size-- * (*isn - '0');
285  }
286  isn++;
287  }
288  weight = weight % 11;
289  if (weight != 0)
290  weight = 11 - weight;
291  return weight;
292 }

Variable Documentation

bool g_initialized = false
static

Definition at line 39 of file isn.c.

Referenced by initialize().

bool g_weak = false
static

Definition at line 38 of file isn.c.

Referenced by accept_weak_input(), string2ean(), and weak_input_status().

const char* const isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"}
static

Definition at line 36 of file isn.c.

Referenced by ean2isn(), ean2string(), and string2ean().

PG_MODULE_MAGIC

Definition at line 27 of file isn.c.