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 ISN_DEBUG   0
 
#define MAXEAN13LEN   18
 

Enumerations

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

Functions

 pg_attribute_unused ()
 
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 _PG_init (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
 

Macro Definition Documentation

#define ISN_DEBUG   0

Definition at line 32 of file isn.c.

Referenced by _PG_init().

#define MAXEAN13LEN   18

Definition at line 35 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 37 of file isn.c.

38 {
40 };
Definition: isn.c:39
Definition: isn.c:39
Definition: isn.c:39
Definition: isn.c:39
Definition: isn.c:39
Definition: isn.c:39
Definition: isn.c:39

Function Documentation

void _PG_init ( void  )

Definition at line 931 of file isn.c.

References EAN13_index, EAN13_range, elog, ERROR, ISBN_index, ISBN_range, ISMN_index, ISMN_range, ISN_DEBUG, ISSN_index, ISSN_range, UPC_index, and UPC_range.

932 {
933  if (ISN_DEBUG)
934  {
935  if (!check_table(EAN13_range, EAN13_index))
936  elog(ERROR, "EAN13 failed check");
937  if (!check_table(ISBN_range, ISBN_index))
938  elog(ERROR, "ISBN failed check");
939  if (!check_table(ISMN_range, ISMN_index))
940  elog(ERROR, "ISMN failed check");
941  if (!check_table(ISSN_range, ISSN_index))
942  elog(ERROR, "ISSN failed check");
943  if (!check_table(UPC_range, UPC_index))
944  elog(ERROR, "UPC failed check");
945  }
946 }
#define ISN_DEBUG
Definition: isn.c:32
const unsigned UPC_index[10][2]
Definition: UPC.h:14
const unsigned ISSN_index[10][2]
Definition: ISSN.h:34
const unsigned EAN13_index[10][2]
Definition: EAN13.h:14
#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 char * ISSN_range[][2]
Definition: ISSN.h:46
const unsigned ISBN_index[10][2]
Definition: ISBN.h:37
const char * ISMN_range[][2]
Definition: ISMN.h:45
const char * ISBN_range[][2]
Definition: ISBN.h:50
#define elog
Definition: elog.h:219
const char * UPC_range[][2]
Definition: UPC.h:26
Datum accept_weak_input ( PG_FUNCTION_ARGS  )

Definition at line 1125 of file isn.c.

References g_weak, PG_GETARG_BOOL, and PG_RETURN_BOOL.

1126 {
1127 #ifdef ISN_WEAK_MODE
1128  g_weak = PG_GETARG_BOOL(0);
1129 #else
1130  /* function has no effect */
1131 #endif /* ISN_WEAK_MODE */
1133 }
static bool g_weak
Definition: isn.c:44
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:239
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
static unsigned checkdig ( char *  num,
unsigned  size 
)
static

Definition at line 305 of file isn.c.

Referenced by string2ean().

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

Definition at line 144 of file isn.c.

Referenced by ean2UPC().

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

Definition at line 984 of file isn.c.

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

985 {
986  const char *str = PG_GETARG_CSTRING(0);
987  ean13 result;
988 
989  (void) string2ean(str, false, &result, EAN13);
990  PG_RETURN_EAN13(result);
991 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:686
Definition: isn.c:39
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Datum ean13_out ( PG_FUNCTION_ARGS  )

Definition at line 968 of file isn.c.

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

969 {
971  char *result;
972  char buf[MAXEAN13LEN + 1];
973 
974  (void) ean2string(val, false, buf, false);
975 
976  result = pstrdup(buf);
977  PG_RETURN_CSTRING(result);
978 }
static bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
Definition: isn.c:534
char * pstrdup(const char *in)
Definition: mcxt.c:1076
uint64 ean13
Definition: isn.h:26
static char * buf
Definition: pg_test_fsync.c:67
#define MAXEAN13LEN
Definition: isn.c:35
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:322
long val
Definition: informix.c:689
static void ean2ISBN ( char *  isn)
inlinestatic

Definition at line 444 of file isn.c.

References hyphenate(), and weight_checkdig().

Referenced by ean2string().

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

Definition at line 469 of file isn.c.

References hyphenate().

Referenced by ean2string().

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

Definition at line 342 of file isn.c.

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

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

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

Definition at line 478 of file isn.c.

References hyphenate(), and weight_checkdig().

Referenced by ean2string().

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

Definition at line 534 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, snprintf(), NODE::type, UPC, UPC_index, and UPC_range.

Referenced by ean13_out(), and isn_out().

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

Definition at line 494 of file isn.c.

References dehyphenate().

Referenced by ean2string().

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

Definition at line 169 of file isn.c.

References lower(), and upper().

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

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

Definition at line 1100 of file isn.c.

References PG_GETARG_EAN13, PG_RETURN_BOOL, and val.

1101 {
1102  ean13 val = PG_GETARG_EAN13(0);
1103 
1104  PG_RETURN_BOOL((val & 1) == 0);
1105 }
uint64 ean13
Definition: isn.h:26
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
long val
Definition: informix.c:689
Datum isbn_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1049 of file isn.c.

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

1050 {
1051  ean13 val = PG_GETARG_EAN13(0);
1052  ean13 result;
1053 
1054  (void) ean2isn(val, false, &result, ISBN);
1055 
1056  PG_RETURN_EAN13(result);
1057 }
Definition: isn.c:39
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:342
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
long val
Definition: informix.c:689
Datum isbn_in ( PG_FUNCTION_ARGS  )

Definition at line 997 of file isn.c.

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

998 {
999  const char *str = PG_GETARG_CSTRING(0);
1000  ean13 result;
1001 
1002  (void) string2ean(str, false, &result, ISBN);
1003  PG_RETURN_EAN13(result);
1004 }
Definition: isn.c:39
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:686
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Datum ismn_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1061 of file isn.c.

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

1062 {
1063  ean13 val = PG_GETARG_EAN13(0);
1064  ean13 result;
1065 
1066  (void) ean2isn(val, false, &result, ISMN);
1067 
1068  PG_RETURN_EAN13(result);
1069 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
Definition: isn.c:39
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:342
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
long val
Definition: informix.c:689
Datum ismn_in ( PG_FUNCTION_ARGS  )

Definition at line 1010 of file isn.c.

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

1011 {
1012  const char *str = PG_GETARG_CSTRING(0);
1013  ean13 result;
1014 
1015  (void) string2ean(str, false, &result, ISMN);
1016  PG_RETURN_EAN13(result);
1017 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
Definition: isn.c:39
uint64 ean13
Definition: isn.h:26
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:686
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Datum isn_out ( PG_FUNCTION_ARGS  )

Definition at line 952 of file isn.c.

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

953 {
955  char *result;
956  char buf[MAXEAN13LEN + 1];
957 
958  (void) ean2string(val, false, buf, true);
959 
960  result = pstrdup(buf);
961  PG_RETURN_CSTRING(result);
962 }
static bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
Definition: isn.c:534
char * pstrdup(const char *in)
Definition: mcxt.c:1076
uint64 ean13
Definition: isn.h:26
static char * buf
Definition: pg_test_fsync.c:67
#define MAXEAN13LEN
Definition: isn.c:35
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:322
long val
Definition: informix.c:689
Datum issn_cast_from_ean13 ( PG_FUNCTION_ARGS  )

Definition at line 1073 of file isn.c.

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

1074 {
1075  ean13 val = PG_GETARG_EAN13(0);
1076  ean13 result;
1077 
1078  (void) ean2isn(val, false, &result, ISSN);
1079 
1080  PG_RETURN_EAN13(result);
1081 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:342
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
Definition: isn.c:39
long val
Definition: informix.c:689
Datum issn_in ( PG_FUNCTION_ARGS  )

Definition at line 1023 of file isn.c.

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

1024 {
1025  const char *str = PG_GETARG_CSTRING(0);
1026  ean13 result;
1027 
1028  (void) string2ean(str, false, &result, ISSN);
1029  PG_RETURN_EAN13(result);
1030 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
Definition: isn.c:39
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:686
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Datum make_valid ( PG_FUNCTION_ARGS  )

Definition at line 1111 of file isn.c.

References PG_GETARG_EAN13, PG_RETURN_EAN13, and val.

1112 {
1113  ean13 val = PG_GETARG_EAN13(0);
1114 
1115  val &= ~((ean13) 1);
1116  PG_RETURN_EAN13(val);
1117 }
#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_attribute_unused ( )

Definition at line 64 of file isn.c.

References DEBUG1, elog, i, and init().

67 {
68  const char *aux1,
69  *aux2;
70  int a,
71  b,
72  x = 0,
73  y = -1,
74  i = 0,
75  j,
76  init = 0;
77 
78  if (TABLE == NULL || TABLE_index == NULL)
79  return true;
80 
81  while (TABLE[i][0] && TABLE[i][1])
82  {
83  aux1 = TABLE[i][0];
84  aux2 = TABLE[i][1];
85 
86  /* must always start with a digit: */
87  if (!isdigit((unsigned char) *aux1) || !isdigit((unsigned char) *aux2))
88  goto invalidtable;
89  a = *aux1 - '0';
90  b = *aux2 - '0';
91 
92  /* must always have the same format and length: */
93  while (*aux1 && *aux2)
94  {
95  if (!(isdigit((unsigned char) *aux1) &&
96  isdigit((unsigned char) *aux2)) &&
97  (*aux1 != *aux2 || *aux1 != '-'))
98  goto invalidtable;
99  aux1++;
100  aux2++;
101  }
102  if (*aux1 != *aux2)
103  goto invalidtable;
104 
105  /* found a new range */
106  if (a > y)
107  {
108  /* check current range in the index: */
109  for (j = x; j <= y; j++)
110  {
111  if (TABLE_index[j][0] != init)
112  goto invalidindex;
113  if (TABLE_index[j][1] != i - init)
114  goto invalidindex;
115  }
116  init = i;
117  x = a;
118  }
119 
120  /* Always get the new limit */
121  y = b;
122  if (y < x)
123  goto invalidtable;
124  i++;
125  }
126 
127  return true;
128 
129 invalidtable:
130  elog(DEBUG1, "invalid table near {\"%s\", \"%s\"} (pos: %d)",
131  TABLE[i][0], TABLE[i][1], i);
132  return false;
133 
134 invalidindex:
135  elog(DEBUG1, "index %d is invalid", j);
136  return false;
137 }
#define DEBUG1
Definition: elog.h:25
static void init(bool is_no_vacuum)
Definition: pgbench.c:2606
int i
#define elog
Definition: elog.h:219
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 510 of file isn.c.

Referenced by string2ean().

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

Definition at line 686 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().

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

Definition at line 1085 of file isn.c.

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

1086 {
1087  ean13 val = PG_GETARG_EAN13(0);
1088  ean13 result;
1089 
1090  (void) ean2isn(val, false, &result, UPC);
1091 
1092  PG_RETURN_EAN13(result);
1093 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:342
#define PG_GETARG_EAN13(n)
Definition: isn.h:30
Definition: isn.c:39
long val
Definition: informix.c:689
Datum upc_in ( PG_FUNCTION_ARGS  )

Definition at line 1036 of file isn.c.

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

1037 {
1038  const char *str = PG_GETARG_CSTRING(0);
1039  ean13 result;
1040 
1041  (void) string2ean(str, false, &result, UPC);
1042  PG_RETURN_EAN13(result);
1043 }
#define PG_RETURN_EAN13(x)
Definition: isn.h:31
uint64 ean13
Definition: isn.h:26
Definition: isn.c:39
static bool string2ean(const char *str, bool errorOK, ean13 *result, enum isn_type accept)
Definition: isn.c:686
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Datum weak_input_status ( PG_FUNCTION_ARGS  )

Definition at line 1137 of file isn.c.

References g_weak, and PG_RETURN_BOOL.

1138 {
1140 }
static bool g_weak
Definition: isn.c:44
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
static unsigned weight_checkdig ( char *  isn,
unsigned  size 
)
static

Definition at line 279 of file isn.c.

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

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

Variable Documentation

bool g_weak = false
static

Definition at line 44 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 42 of file isn.c.

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

PG_MODULE_MAGIC

Definition at line 27 of file isn.c.