#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"
Go to the source code of this file.
Defines | |
| #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 |
| #define MAXEAN13LEN 18 |
Definition at line 29 of file isn.c.
Referenced by ean13_out(), ean2isn(), and isn_out().
| enum isn_type |
| Datum accept_weak_input | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1113 of file isn.c.
References g_weak, PG_GETARG_BOOL, and PG_RETURN_BOOL.
{
#ifdef ISN_WEAK_MODE
g_weak = PG_GETARG_BOOL(0);
#else
/* function has no effect */
#endif /* ISN_WEAK_MODE */
PG_RETURN_BOOL(g_weak);
}
| static unsigned checkdig | ( | char * | num, | |
| unsigned | size | |||
| ) | [static] |
Definition at line 302 of file isn.c.
Referenced by string2ean().
{
unsigned check = 0,
check3 = 0;
unsigned pos = 0;
if (*num == 'M')
{ /* ISMN start with 'M' */
check3 = 3;
pos = 1;
}
while (*num && size > 1)
{
if (isdigit((unsigned char) *num))
{
if (pos++ % 2)
check3 += *num - '0';
else
check += *num - '0';
size--;
}
num++;
}
check = (check + 3 * check3) % 10;
if (check != 0)
check = 10 - check;
return check;
}
| static unsigned dehyphenate | ( | char * | bufO, | |
| char * | bufI | |||
| ) | [static] |
| Datum ean13_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 972 of file isn.c.
References EAN13, PG_GETARG_CSTRING, PG_RETURN_EAN13, and string2ean().
{
const char *str = PG_GETARG_CSTRING(0);
ean13 result;
(void) string2ean(str, false, &result, EAN13);
PG_RETURN_EAN13(result);
}
| Datum ean13_out | ( | PG_FUNCTION_ARGS | ) |
Definition at line 956 of file isn.c.
References buf, ean2string(), MAXEAN13LEN, PG_GETARG_EAN13, PG_RETURN_CSTRING, pstrdup(), and val.
{
ean13 val = PG_GETARG_EAN13(0);
char *result;
char buf[MAXEAN13LEN + 1];
(void) ean2string(val, false, buf, false);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
}
| static void ean2ISBN | ( | char * | isn | ) | [inline, static] |
Definition at line 441 of file isn.c.
References hyphenate(), NULL, and weight_checkdig().
Referenced by ean2string().
{
char *aux;
unsigned check;
/* the number should come in this format: 978-0-000-00000-0 */
/* Strip the first part and calculate the new check digit */
hyphenate(isn, isn + 4, NULL, NULL);
check = weight_checkdig(isn, 10);
aux = strchr(isn, '\0');
while (!isdigit((unsigned char) *--aux));
if (check == 10)
*aux = 'X';
else
*aux = check + '0';
}
| static void ean2ISMN | ( | char * | isn | ) | [inline, static] |
Definition at line 339 of file isn.c.
References ANY, buf, EAN13, EAN13_FORMAT, ereport, errcode(), errmsg(), ERROR, isn_names, MAXEAN13LEN, snprintf(), NODE::type, and UINT64CONST.
Referenced by isbn_cast_from_ean13(), ismn_cast_from_ean13(), issn_cast_from_ean13(), and upc_cast_from_ean13().
{
enum isn_type type = INVALID;
char buf[MAXEAN13LEN + 1];
char *aux;
unsigned digval;
unsigned search;
ean13 ret = ean;
ean >>= 1;
/* verify it's in the EAN13 range */
if (ean > UINT64CONST(9999999999999))
goto eantoobig;
/* convert the number */
search = 0;
aux = buf + 13;
*aux = '\0'; /* terminate string; aux points to last digit */
do
{
digval = (unsigned) (ean % 10); /* get the decimal value */
ean /= 10; /* get next digit */
*--aux = (char) (digval + '0'); /* convert to ascii and store */
} while (ean && search++ < 12);
while (search++ < 12)
*--aux = '0'; /* fill the remaining EAN13 with '0' */
/* find out the data type: */
if (strncmp("978", buf, 3) == 0)
{ /* ISBN */
type = ISBN;
}
else if (strncmp("977", buf, 3) == 0)
{ /* ISSN */
type = ISSN;
}
else if (strncmp("9790", buf, 4) == 0)
{ /* ISMN */
type = ISMN;
}
else if (strncmp("979", buf, 3) == 0)
{ /* ISBN-13 */
type = ISBN;
}
else if (*buf == '0')
{ /* UPC */
type = UPC;
}
else
{
type = EAN13;
}
if (accept != ANY && accept != EAN13 && accept != type)
goto eanwrongtype;
*result = ret;
return true;
eanwrongtype:
if (!errorOK)
{
if (type != EAN13)
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",
isn_names[type], isn_names[accept], buf)));
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("cannot cast %s to %s for number: \"%s\"",
isn_names[type], isn_names[accept], buf)));
}
}
return false;
eantoobig:
if (!errorOK)
{
char eanbuf[64];
/*
* Format the number separately to keep the machine-dependent format
* code out of the translatable message text
*/
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for %s type",
eanbuf, isn_names[type])));
}
return false;
}
| static void ean2ISSN | ( | char * | isn | ) | [inline, static] |
Definition at line 468 of file isn.c.
References hyphenate(), NULL, and weight_checkdig().
Referenced by ean2string().
{
unsigned check;
/* the number should come in this format: 977-0000-000-00-0 */
/* Strip the first part, crop, and calculate the new check digit */
hyphenate(isn, isn + 4, NULL, NULL);
check = weight_checkdig(isn, 8);
if (check == 10)
isn[8] = 'X';
else
isn[8] = check + '0';
isn[9] = '\0';
}
Definition at line 524 of file isn.c.
References EAN13_FORMAT, EAN13_index, EAN13_range, ean2ISBN(), ean2ISMN(), ean2ISSN(), ean2UPC(), ereport, errcode(), errmsg(), ERROR, hyphenate(), ISBN, ISBN_index, ISBN_index_new, ISBN_range, ISBN_range_new, ISMN, ISMN_index, ISMN_range, isn_names, ISSN, ISSN_index, ISSN_range, NULL, snprintf(), NODE::type, UINT64CONST, UPC, UPC_index, and UPC_range.
Referenced by ean13_out(), and isn_out().
{
const char *(*TABLE)[2];
const unsigned (*TABLE_index)[2];
enum isn_type type = INVALID;
char *aux;
unsigned digval;
unsigned search;
char valid = '\0'; /* was the number initially written with a
* valid check digit? */
TABLE_index = ISBN_index;
if ((ean & 1) != 0)
valid = '!';
ean >>= 1;
/* verify it's in the EAN13 range */
if (ean > UINT64CONST(9999999999999))
goto eantoobig;
/* convert the number */
search = 0;
aux = result + MAXEAN13LEN;
*aux = '\0'; /* terminate string; aux points to last digit */
*--aux = valid; /* append '!' for numbers with invalid but
* corrected check digit */
do
{
digval = (unsigned) (ean % 10); /* get the decimal value */
ean /= 10; /* get next digit */
*--aux = (char) (digval + '0'); /* convert to ascii and store */
if (search == 0)
*--aux = '-'; /* the check digit is always there */
} while (ean && search++ < 13);
while (search++ < 13)
*--aux = '0'; /* fill the remaining EAN13 with '0' */
/* The string should be in this form: ???DDDDDDDDDDDD-D" */
search = hyphenate(result, result + 3, EAN13_range, EAN13_index);
/* verify it's a logically valid EAN13 */
if (search == 0)
{
search = hyphenate(result, result + 3, NULL, NULL);
goto okay;
}
/* find out what type of hyphenation is needed: */
if (strncmp("978-", result, search) == 0)
{ /* ISBN -13 978-range */
/* The string should be in this form: 978-??000000000-0" */
type = ISBN;
TABLE = ISBN_range;
TABLE_index = ISBN_index;
}
else if (strncmp("977-", result, search) == 0)
{ /* ISSN */
/* The string should be in this form: 977-??000000000-0" */
type = ISSN;
TABLE = ISSN_range;
TABLE_index = ISSN_index;
}
else if (strncmp("979-0", result, search + 1) == 0)
{ /* ISMN */
/* The string should be in this form: 979-0?000000000-0" */
type = ISMN;
TABLE = ISMN_range;
TABLE_index = ISMN_index;
}
else if (strncmp("979-", result, search) == 0)
{ /* ISBN-13 979-range */
/* The string should be in this form: 979-??000000000-0" */
type = ISBN;
TABLE = ISBN_range_new;
TABLE_index = ISBN_index_new;
}
else if (*result == '0')
{ /* UPC */
/* The string should be in this form: 000-00000000000-0" */
type = UPC;
TABLE = UPC_range;
TABLE_index = UPC_index;
}
else
{
type = EAN13;
TABLE = NULL;
TABLE_index = NULL;
}
/* verify it's a logically valid EAN13/UPC/ISxN */
digval = search;
search = hyphenate(result + digval, result + digval + 2, TABLE, TABLE_index);
/* verify it's a valid EAN13 */
if (search == 0)
{
search = hyphenate(result + digval, result + digval + 2, NULL, NULL);
goto okay;
}
okay:
/* convert to the old short type: */
if (shortType)
switch (type)
{
case ISBN:
ean2ISBN(result);
break;
case ISMN:
ean2ISMN(result);
break;
case ISSN:
ean2ISSN(result);
break;
case UPC:
ean2UPC(result);
break;
default:
break;
}
return true;
eantoobig:
if (!errorOK)
{
char eanbuf[64];
/*
* Format the number separately to keep the machine-dependent format
* code out of the translatable message text
*/
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for %s type",
eanbuf, isn_names[type])));
}
return false;
}
| static void ean2UPC | ( | char * | isn | ) | [inline, static] |
Definition at line 484 of file isn.c.
References dehyphenate().
Referenced by ean2string().
{
/* the number should come in this format: 000-000000000-0 */
/* Strip the first part, crop, and dehyphenate */
dehyphenate(isn, isn + 1);
isn[12] = '\0';
}
| 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 NULL.
Referenced by ean2ISBN(), ean2ISMN(), ean2ISSN(), and ean2string().
{
unsigned ret = 0;
const char *ean_aux1,
*ean_aux2,
*ean_p;
char *firstdig,
*aux1,
*aux2;
unsigned search,
upper,
lower,
step;
bool ean_in1,
ean_in2;
/* just compress the string if no further hyphenation is required */
if (TABLE == NULL || TABLE_index == NULL)
{
while (*bufI)
{
*bufO++ = *bufI++;
ret++;
}
*bufO = '\0';
return (ret + 1);
}
/* add remaining hyphenations */
search = *bufI - '0';
upper = lower = TABLE_index[search][0];
upper += TABLE_index[search][1];
lower--;
step = (upper - lower) / 2;
if (step == 0)
return 0;
search = lower + step;
firstdig = bufI;
ean_in1 = ean_in2 = false;
ean_aux1 = TABLE[search][0];
ean_aux2 = TABLE[search][1];
do
{
if ((ean_in1 || *firstdig >= *ean_aux1) && (ean_in2 || *firstdig <= *ean_aux2))
{
if (*firstdig > *ean_aux1)
ean_in1 = true;
if (*firstdig < *ean_aux2)
ean_in2 = true;
if (ean_in1 && ean_in2)
break;
firstdig++, ean_aux1++, ean_aux2++;
if (!(*ean_aux1 && *ean_aux2 && *firstdig))
break;
if (!isdigit((unsigned char) *ean_aux1))
ean_aux1++, ean_aux2++;
}
else
{
/*
* check in what direction we should go and move the pointer
* accordingly
*/
if (*firstdig < *ean_aux1 && !ean_in1)
upper = search;
else
lower = search;
step = (upper - lower) / 2;
search = lower + step;
/* Initialize stuff again: */
firstdig = bufI;
ean_in1 = ean_in2 = false;
ean_aux1 = TABLE[search][0];
ean_aux2 = TABLE[search][1];
}
} while (step);
if (step)
{
aux1 = bufO;
aux2 = bufI;
ean_p = TABLE[search][0];
while (*ean_p && *aux2)
{
if (*ean_p++ != '-')
*aux1++ = *aux2++;
else
*aux1++ = '-';
ret++;
}
*aux1++ = '-';
*aux1 = *aux2; /* add a lookahead char */
return (ret + 1);
}
return ret;
}
| void initialize | ( | void | ) |
Definition at line 919 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 longest(), and shortest().
{
#ifdef ISN_DEBUG
if (!check_table(EAN13, EAN13_index))
elog(LOG, "EAN13 failed check");
if (!check_table(ISBN, ISBN_index))
elog(LOG, "ISBN failed check");
if (!check_table(ISMN, ISMN_index))
elog(LOG, "ISMN failed check");
if (!check_table(ISSN, ISSN_index))
elog(LOG, "ISSN failed check");
if (!check_table(UPC, UPC_index))
elog(LOG, "UPC failed check");
#endif
g_initialized = true;
}
| Datum is_valid | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1088 of file isn.c.
References PG_GETARG_EAN13, PG_RETURN_BOOL, and val.
{
ean13 val = PG_GETARG_EAN13(0);
PG_RETURN_BOOL((val & 1) == 0);
}
| Datum isbn_cast_from_ean13 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1037 of file isn.c.
References ean2isn(), ISBN, PG_GETARG_EAN13, PG_RETURN_EAN13, and val.
{
ean13 val = PG_GETARG_EAN13(0);
ean13 result;
(void) ean2isn(val, false, &result, ISBN);
PG_RETURN_EAN13(result);
}
| Datum isbn_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 985 of file isn.c.
References ISBN, PG_GETARG_CSTRING, PG_RETURN_EAN13, and string2ean().
{
const char *str = PG_GETARG_CSTRING(0);
ean13 result;
(void) string2ean(str, false, &result, ISBN);
PG_RETURN_EAN13(result);
}
| Datum ismn_cast_from_ean13 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1049 of file isn.c.
References ean2isn(), ISMN, PG_GETARG_EAN13, PG_RETURN_EAN13, and val.
{
ean13 val = PG_GETARG_EAN13(0);
ean13 result;
(void) ean2isn(val, false, &result, ISMN);
PG_RETURN_EAN13(result);
}
| Datum ismn_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 998 of file isn.c.
References ISMN, PG_GETARG_CSTRING, PG_RETURN_EAN13, and string2ean().
{
const char *str = PG_GETARG_CSTRING(0);
ean13 result;
(void) string2ean(str, false, &result, ISMN);
PG_RETURN_EAN13(result);
}
| Datum isn_out | ( | PG_FUNCTION_ARGS | ) |
Definition at line 940 of file isn.c.
References buf, ean2string(), MAXEAN13LEN, PG_GETARG_EAN13, PG_RETURN_CSTRING, pstrdup(), and val.
{
ean13 val = PG_GETARG_EAN13(0);
char *result;
char buf[MAXEAN13LEN + 1];
(void) ean2string(val, false, buf, true);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
}
| Datum issn_cast_from_ean13 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1061 of file isn.c.
References ean2isn(), ISSN, PG_GETARG_EAN13, PG_RETURN_EAN13, and val.
{
ean13 val = PG_GETARG_EAN13(0);
ean13 result;
(void) ean2isn(val, false, &result, ISSN);
PG_RETURN_EAN13(result);
}
| Datum issn_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1011 of file isn.c.
References ISSN, PG_GETARG_CSTRING, PG_RETURN_EAN13, and string2ean().
{
const char *str = PG_GETARG_CSTRING(0);
ean13 result;
(void) string2ean(str, false, &result, ISSN);
PG_RETURN_EAN13(result);
}
| Datum make_valid | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1099 of file isn.c.
References PG_GETARG_EAN13, PG_RETURN_EAN13, and val.
{
ean13 val = PG_GETARG_EAN13(0);
val &= ~((ean13) 1);
PG_RETURN_EAN13(val);
}
| PG_FUNCTION_INFO_V1 | ( | ean13_out | ) |
| PG_FUNCTION_INFO_V1 | ( | isbn_in | ) |
| PG_FUNCTION_INFO_V1 | ( | accept_weak_input | ) |
| PG_FUNCTION_INFO_V1 | ( | issn_cast_from_ean13 | ) |
| PG_FUNCTION_INFO_V1 | ( | upc_cast_from_ean13 | ) |
| PG_FUNCTION_INFO_V1 | ( | ean13_in | ) |
| PG_FUNCTION_INFO_V1 | ( | isn_out | ) |
| PG_FUNCTION_INFO_V1 | ( | ismn_cast_from_ean13 | ) |
| PG_FUNCTION_INFO_V1 | ( | weak_input_status | ) |
| PG_FUNCTION_INFO_V1 | ( | upc_in | ) |
| PG_FUNCTION_INFO_V1 | ( | is_valid | ) |
| PG_FUNCTION_INFO_V1 | ( | ismn_in | ) |
| PG_FUNCTION_INFO_V1 | ( | make_valid | ) |
| PG_FUNCTION_INFO_V1 | ( | issn_in | ) |
| PG_FUNCTION_INFO_V1 | ( | isbn_cast_from_ean13 | ) |
| static ean13 str2ean | ( | const char * | num | ) | [static] |
Definition at line 500 of file isn.c.
Referenced by string2ean().
{
ean13 ean = 0; /* current ean */
while (*num)
{
if (isdigit((unsigned char) *num))
ean = 10 * ean + (*num - '0');
num++;
}
return (ean << 1); /* also give room to a flag */
}
| static bool string2ean | ( | const char * | str, | |
| bool | errorOK, | |||
| ean13 * | result, | |||
| enum isn_type | accept | |||
| ) | [static] |
Definition at line 676 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().
{
bool digit,
last;
char buf[17] = " ";
char *aux1 = buf + 3; /* leave space for the first part, in case
* it's needed */
const char *aux2 = str;
enum isn_type type = INVALID;
unsigned check = 0,
rcheck = (unsigned) -1;
unsigned length = 0;
bool magic = false,
valid = true;
/* recognize and validate the number: */
while (*aux2 && length <= 13)
{
last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0'); /* is the last character */
digit = (isdigit((unsigned char) *aux2) != 0); /* is current character
* a digit? */
if (*aux2 == '?' && last) /* automagically calculate check digit
* if it's '?' */
magic = digit = true;
if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))
{
/* only ISMN can be here */
if (type != INVALID)
goto eaninvalid;
type = ISMN;
*aux1++ = 'M';
length++;
}
else if (length == 7 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
{
/* only ISSN can be here */
if (type != INVALID)
goto eaninvalid;
type = ISSN;
*aux1++ = toupper((unsigned char) *aux2);
length++;
}
else if (length == 9 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
{
/* only ISBN and ISMN can be here */
if (type != INVALID && type != ISMN)
goto eaninvalid;
if (type == INVALID)
type = ISBN; /* ISMN must start with 'M' */
*aux1++ = toupper((unsigned char) *aux2);
length++;
}
else if (length == 11 && digit && last)
{
/* only UPC can be here */
if (type != INVALID)
goto eaninvalid;
type = UPC;
*aux1++ = *aux2;
length++;
}
else if (*aux2 == '-' || *aux2 == ' ')
{
/* skip, we could validate but I think it's worthless */
}
else if (*aux2 == '!' && *(aux2 + 1) == '\0')
{
/* the invalid check digit sufix was found, set it */
if (!magic)
valid = false;
magic = true;
}
else if (!digit)
{
goto eaninvalid;
}
else
{
*aux1++ = *aux2;
if (++length > 13)
goto eantoobig;
}
aux2++;
}
*aux1 = '\0'; /* terminate the string */
/* find the current check digit value */
if (length == 13)
{
/* only EAN13 can be here */
if (type != INVALID)
goto eaninvalid;
type = EAN13;
check = buf[15] - '0';
}
else if (length == 12)
{
/* only UPC can be here */
if (type != UPC)
goto eaninvalid;
check = buf[14] - '0';
}
else if (length == 10)
{
if (type != ISBN && type != ISMN)
goto eaninvalid;
if (buf[12] == 'X')
check = 10;
else
check = buf[12] - '0';
}
else if (length == 8)
{
if (type != INVALID && type != ISSN)
goto eaninvalid;
type = ISSN;
if (buf[10] == 'X')
check = 10;
else
check = buf[10] - '0';
}
else
goto eaninvalid;
if (type == INVALID)
goto eaninvalid;
/* obtain the real check digit value, validate, and convert to ean13: */
if (accept == EAN13 && type != accept)
goto eanwrongtype;
if (accept != ANY && type != EAN13 && type != accept)
goto eanwrongtype;
switch (type)
{
case EAN13:
valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));
/* now get the subtype of EAN13: */
if (buf[3] == '0')
type = UPC;
else if (strncmp("977", buf + 3, 3) == 0)
type = ISSN;
else if (strncmp("978", buf + 3, 3) == 0)
type = ISBN;
else if (strncmp("9790", buf + 3, 4) == 0)
type = ISMN;
else if (strncmp("979", buf + 3, 3) == 0)
type = ISBN;
if (accept != EAN13 && accept != ANY && type != accept)
goto eanwrongtype;
break;
case ISMN:
strncpy(buf, "9790", 4); /* this isn't for sure yet, for now
* ISMN it's only 9790 */
valid = (valid && ((rcheck = checkdig(buf + 3, 10)) == check || magic));
break;
case ISBN:
strncpy(buf, "978", 3);
valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
break;
case ISSN:
strncpy(buf + 10, "00", 2); /* append 00 as the normal issue
* publication code */
strncpy(buf, "977", 3);
valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));
break;
case UPC:
buf[2] = '0';
valid = (valid && ((rcheck = checkdig(buf + 2, 13)) == check || magic));
default:
break;
}
/* fix the check digit: */
for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
aux1[12] = checkdig(aux1, 13) + '0';
aux1[13] = '\0';
if (!valid && !magic)
goto eanbadcheck;
*result = str2ean(aux1);
*result |= valid ? 0 : 1;
return true;
eanbadcheck:
if (g_weak)
{ /* weak input mode is activated: */
/* set the "invalid-check-digit-on-input" flag */
*result = str2ean(aux1);
*result |= 1;
return true;
}
if (!errorOK)
{
if (rcheck == (unsigned) -1)
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid %s number: \"%s\"",
isn_names[accept], str)));
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid check digit for %s number: \"%s\", should be %c",
isn_names[accept], str, (rcheck == 10) ? ('X') : (rcheck + '0'))));
}
}
return false;
eaninvalid:
if (!errorOK)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for %s number: \"%s\"",
isn_names[accept], str)));
return false;
eanwrongtype:
if (!errorOK)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("cannot cast %s to %s for number: \"%s\"",
isn_names[type], isn_names[accept], str)));
return false;
eantoobig:
if (!errorOK)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for %s type",
str, isn_names[accept])));
return false;
}
| Datum upc_cast_from_ean13 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1073 of file isn.c.
References ean2isn(), PG_GETARG_EAN13, PG_RETURN_EAN13, UPC, and val.
{
ean13 val = PG_GETARG_EAN13(0);
ean13 result;
(void) ean2isn(val, false, &result, UPC);
PG_RETURN_EAN13(result);
}
| Datum upc_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1024 of file isn.c.
References PG_GETARG_CSTRING, PG_RETURN_EAN13, string2ean(), and UPC.
{
const char *str = PG_GETARG_CSTRING(0);
ean13 result;
(void) string2ean(str, false, &result, UPC);
PG_RETURN_EAN13(result);
}
| Datum weak_input_status | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1125 of file isn.c.
References g_weak, and PG_RETURN_BOOL.
{
PG_RETURN_BOOL(g_weak);
}
| static unsigned weight_checkdig | ( | char * | isn, | |
| unsigned | size | |||
| ) | [static] |
Definition at line 276 of file isn.c.
Referenced by ean2ISBN(), ean2ISSN(), and string2ean().
{
unsigned weight = 0;
while (*isn && size > 1)
{
if (isdigit((unsigned char) *isn))
{
weight += size-- * (*isn - '0');
}
isn++;
}
weight = weight % 11;
if (weight != 0)
weight = 11 - weight;
return weight;
}
bool g_initialized = false [static] |
Definition at line 39 of file isn.c.
Referenced by initialize().
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().
1.7.1