#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().