* isn.c
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
*
- * Copyright (c) 2004-2006, Germán Méndez Bravo (Kronuz)
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Author: German Mendez Bravo (Kronuz)
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.5 2007/01/05 22:19:18 momjian Exp $
+ * contrib/isn/isn.c
*
*-------------------------------------------------------------------------
*/
#include "fmgr.h"
#include "utils/builtins.h"
-PG_MODULE_MAGIC;
-
#include "isn.h"
-
#include "EAN13.h"
#include "ISBN.h"
#include "ISMN.h"
#include "ISSN.h"
#include "UPC.h"
+PG_MODULE_MAGIC;
+
#define MAXEAN13LEN 18
enum isn_type
INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC
};
-static const char *isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"};
+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;
-/* Macros for converting TEXT to and from c-string */
-#define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
-#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
-
/***********************************************************************
**
* Check if the table and its index is correct (just for debugging)
*/
#ifdef ISN_DEBUG
-static
-bool
+static bool
check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
{
const char *aux1,
* Formatting and conversion routines.
*---------------------------------------------------------*/
-static
-unsigned
+static unsigned
dehyphenate(char *bufO, char *bufI)
{
unsigned ret = 0;
*
* Returns the number of characters acctually hyphenated.
*/
-static
-unsigned
+static unsigned
hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
{
unsigned ret = 0;
*
* Returns the weight of the number (the check digit value, 0-10)
*/
-static
-unsigned
+static unsigned
weight_checkdig(char *isn, unsigned size)
{
unsigned weight = 0;
*
* Returns the check digit value (0-9)
*/
-static
-unsigned
+static unsigned
checkdig(char *num, unsigned size)
{
unsigned check = 0,
* If errorOK is false, ereport a useful error message if the ean13 is bad.
* If errorOK is true, just return "false" for bad input.
*/
-static
-bool
-ean2isn(ean13 ean, bool errorOK, ean13 * result, enum isn_type accept)
+static bool
+ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
{
enum isn_type type = INVALID;
char buf[MAXEAN13LEN + 1];
- char *firstdig,
- *aux;
+ char *aux;
unsigned digval;
unsigned search;
ean13 ret = ean;
/* convert the number */
search = 0;
- firstdig = aux = buf + 13;
+ aux = buf + 13;
*aux = '\0'; /* terminate string; aux points to last digit */
do
{
*--aux = '0'; /* fill the remaining EAN13 with '0' */
/* find out the data type: */
- if (!strncmp("978", buf, 3))
+ if (strncmp("978", buf, 3) == 0)
{ /* ISBN */
type = ISBN;
}
- else if (!strncmp("977", buf, 3))
+ else if (strncmp("977", buf, 3) == 0)
{ /* ISSN */
type = ISSN;
}
- else if (!strncmp("9790", buf, 4))
+ else if (strncmp("9790", buf, 4) == 0)
{ /* ISMN */
type = ISMN;
}
- else if (!strncmp("979", buf, 3))
+ else if (strncmp("979", buf, 3) == 0)
{ /* ISBN-13 */
type = ISBN;
}
* ean2UPC/ISxN --- Convert in-place a normalized EAN13 string to the corresponding
* UPC/ISxN string number. Assumes the input string is normalized.
*/
-static inline
-void
+static inline void
ean2ISBN(char *isn)
{
char *aux;
else
*aux = check + '0';
}
-static inline
-void
+
+static inline void
ean2ISMN(char *isn)
{
/* the number should come in this format: 979-0-000-00000-0 */
hyphenate(isn, isn + 4, NULL, NULL);
isn[0] = 'M';
}
-static inline
-void
+
+static inline void
ean2ISSN(char *isn)
{
unsigned check;
isn[8] = check + '0';
isn[9] = '\0';
}
-static inline
-void
+
+static inline void
ean2UPC(char *isn)
{
/* the number should come in this format: 000-000000000-0 */
*
* Returns the ean13 value of the string.
*/
-static
-ean13
+static ean13
str2ean(const char *num)
{
ean13 ean = 0; /* current ean */
* If errorOK is false, ereport a useful error message if the string is bad.
* If errorOK is true, just return "false" for bad input.
*/
-static
-bool
+static bool
ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
{
const char *(*TABLE)[2];
const unsigned (*TABLE_index)[2];
enum isn_type type = INVALID;
- char *firstdig,
- *aux;
+ char *aux;
unsigned digval;
unsigned search;
char valid = '\0'; /* was the number initially written with a
/* convert the number */
search = 0;
- firstdig = aux = result + MAXEAN13LEN;
+ aux = result + MAXEAN13LEN;
*aux = '\0'; /* terminate string; aux points to last digit */
*--aux = valid; /* append '!' for numbers with invalid but
* corrected check digit */
}
/* find out what type of hyphenation is needed: */
- if (!strncmp("978-", result, search))
- { /* ISBN */
+ 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))
+ 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))
+ 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" */
* if the input string ends with '!' it will always be treated as invalid
* (even if the check digit is valid)
*/
-static
-bool
-string2ean(const char *str, bool errorOK, ean13 * result,
+static bool
+string2ean(const char *str, bool errorOK, ean13 *result,
enum isn_type accept)
{
bool digit,
/* now get the subtype of EAN13: */
if (buf[3] == '0')
type = UPC;
- else if (!strncmp("977", buf + 3, 3))
+ else if (strncmp("977", buf + 3, 3) == 0)
type = ISSN;
- else if (!strncmp("978", buf + 3, 3))
+ else if (strncmp("978", buf + 3, 3) == 0)
type = ISBN;
- else if (!strncmp("9790", buf + 3, 4))
+ else if (strncmp("9790", buf + 3, 4) == 0)
type = ISMN;
- else if (!strncmp("979", buf + 3, 3))
+ else if (strncmp("979", buf + 3, 3) == 0)
type = ISBN;
if (accept != EAN13 && accept != ANY && type != accept)
goto eanwrongtype;
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));
+ valid = (valid && ((rcheck = checkdig(buf, 13)) == check || magic));
break;
case ISBN:
strncpy(buf, "978", 3);
/* casting functions
*/
-PG_FUNCTION_INFO_V1(ean13_cast_to_text);
-Datum
-ean13_cast_to_text(PG_FUNCTION_ARGS)
-{
- ean13 val = PG_GETARG_EAN13(0);
- char buf[MAXEAN13LEN + 1];
-
- (void) ean2string(val, false, buf, false);
-
- PG_RETURN_TEXT_P(GET_TEXT(buf));
-}
-
-PG_FUNCTION_INFO_V1(isn_cast_to_text);
-Datum
-isn_cast_to_text(PG_FUNCTION_ARGS)
-{
- ean13 val = PG_GETARG_EAN13(0);
- char buf[MAXEAN13LEN + 1];
-
- (void) ean2string(val, false, buf, true);
-
- PG_RETURN_TEXT_P(GET_TEXT(buf));
-}
-
PG_FUNCTION_INFO_V1(isbn_cast_from_ean13);
Datum
isbn_cast_from_ean13(PG_FUNCTION_ARGS)
}
-PG_FUNCTION_INFO_V1(ean13_cast_from_text);
-Datum
-ean13_cast_from_text(PG_FUNCTION_ARGS)
-{
- const char *str = GET_STR(PG_GETARG_TEXT_P(0));
- ean13 result;
-
- (void) string2ean(str, false, &result, EAN13);
- PG_RETURN_EAN13(result);
-}
-
-PG_FUNCTION_INFO_V1(isbn_cast_from_text);
-Datum
-isbn_cast_from_text(PG_FUNCTION_ARGS)
-{
- const char *str = GET_STR(PG_GETARG_TEXT_P(0));
- ean13 result;
-
- (void) string2ean(str, false, &result, ISBN);
- PG_RETURN_EAN13(result);
-}
-
-PG_FUNCTION_INFO_V1(ismn_cast_from_text);
-Datum
-ismn_cast_from_text(PG_FUNCTION_ARGS)
-{
- const char *str = GET_STR(PG_GETARG_TEXT_P(0));
- ean13 result;
-
- (void) string2ean(str, false, &result, ISMN);
- PG_RETURN_EAN13(result);
-}
-
-PG_FUNCTION_INFO_V1(issn_cast_from_text);
-Datum
-issn_cast_from_text(PG_FUNCTION_ARGS)
-{
- const char *str = GET_STR(PG_GETARG_TEXT_P(0));
- ean13 result;
-
- (void) string2ean(str, false, &result, ISSN);
- PG_RETURN_EAN13(result);
-}
-
-PG_FUNCTION_INFO_V1(upc_cast_from_text);
-Datum
-upc_cast_from_text(PG_FUNCTION_ARGS)
-{
- const char *str = GET_STR(PG_GETARG_TEXT_P(0));
- ean13 result;
-
- (void) string2ean(str, false, &result, UPC);
- PG_RETURN_EAN13(result);
-}
-
/* is_valid - returns false if the "invalid-check-digit-on-input" is set
*/
PG_FUNCTION_INFO_V1(is_valid);
PG_RETURN_EAN13(val);
}
-#ifdef ISN_WEAK_MODE
/* this function temporarily sets weak input flag
* (to lose the strictness of check digit acceptance)
* It's a helper function, not intended to be used!!
Datum
accept_weak_input(PG_FUNCTION_ARGS)
{
+#ifdef ISN_WEAK_MODE
g_weak = PG_GETARG_BOOL(0);
- PG_RETURN_BOOL(g_weak);
-}
#else
-PG_FUNCTION_INFO_V1(accept_weak_input);
-Datum
-accept_weak_input(PG_FUNCTION_ARGS)
-{
/* function has no effect */
- PG_RETURN_BOOL(false);
-}
#endif /* ISN_WEAK_MODE */
+ PG_RETURN_BOOL(g_weak);
+}
PG_FUNCTION_INFO_V1(weak_input_status);
Datum