Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  isn.c   Sprache: C

 

/*-------------------------------------------------------------------------
 *
 * isn.c
 *   PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
 *
 * Author: German Mendez Bravo (Kronuz)
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *   contrib/isn/isn.c
 *
 *-------------------------------------------------------------------------
 */


#include "postgres.h"

#include "EAN13.h"
#include "ISBN.h"
#include "ISMN.h"
#include "ISSN.h"
#include "UPC.h"
#include "fmgr.h"
#include "isn.h"
#include "utils/guc.h"

PG_MODULE_MAGIC_EXT(
     .name = "isn",
     .version = PG_VERSION
);

#ifdef USE_ASSERT_CHECKING
#define ISN_DEBUG 1
#else
#define ISN_DEBUG 0
#endif

#define MAXEAN13LEN 18

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

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

/* GUC value */
static bool g_weak = false;


/***********************************************************************
 **
 **  Routines for EAN13/UPC/ISxNs.
 **
 ** Note:
 **  In this code, a normalized string is one that is known to be a valid
 **  ISxN number containing only digits and hyphens and with enough space
 **  to hold the full 13 digits plus the maximum of four hyphens.
 ***********************************************************************/


/*----------------------------------------------------------
 * Debugging routines.
 *---------------------------------------------------------*/


/*
 * Check if the table and its index is correct (just for debugging)
 */

pg_attribute_unused()
static bool
check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
{
 const char *aux1,
      *aux2;
 int   a,
    b,
    x = 0,
    y = -1,
    i = 0,
    j,
    init = 0;

 if (TABLE == NULL || TABLE_index == NULL)
  return true;

 while (TABLE[i][0] && TABLE[i][1])
 {
  aux1 = TABLE[i][0];
  aux2 = TABLE[i][1];

  /* must always start with a digit: */
  if (!isdigit((unsigned char) *aux1) || !isdigit((unsigned char) *aux2))
   goto invalidtable;
  a = *aux1 - '0';
  b = *aux2 - '0';

  /* must always have the same format and length: */
  while (*aux1 && *aux2)
  {
   if (!(isdigit((unsigned char) *aux1) &&
      isdigit((unsigned char) *aux2)) &&
    (*aux1 != *aux2 || *aux1 != '-'))
    goto invalidtable;
   aux1++;
   aux2++;
  }
  if (*aux1 != *aux2)
   goto invalidtable;

  /* found a new range */
  if (a > y)
  {
   /* check current range in the index: */
   for (j = x; j <= y; j++)
   {
    if (TABLE_index[j][0] != init)
     goto invalidindex;
    if (TABLE_index[j][1] != i - init)
     goto invalidindex;
   }
   init = i;
   x = a;
  }

  /* Always get the new limit */
  y = b;
  if (y < x)
   goto invalidtable;
  i++;
 }

 return true;

invalidtable:
 elog(DEBUG1, "invalid table near {\"%s\", \"%s\"} (pos: %d)",
   TABLE[i][0], TABLE[i][1], i);
 return false;

invalidindex:
 elog(DEBUG1, "index %d is invalid", j);
 return false;
}

/*----------------------------------------------------------
 * Formatting and conversion routines.
 *---------------------------------------------------------*/


static unsigned
dehyphenate(char *bufO, char *bufI)
{
 unsigned ret = 0;

 while (*bufI)
 {
  if (isdigit((unsigned char) *bufI))
  {
   *bufO++ = *bufI;
   ret++;
  }
  bufI++;
 }
 *bufO = '\0';
 return ret;
}

/*
 * hyphenate --- Try to hyphenate, in-place, the string starting at bufI
 *      into bufO using the given hyphenation range TABLE.
 *      Assumes the input string to be used is of only digits.
 *
 * Returns the number of characters actually hyphenated.
 */

static unsigned
hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
{
 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;
}

/*
 * weight_checkdig -- Receives a buffer with a normalized ISxN string number,
 *        and the length to weight.
 *
 * Returns the weight of the number (the check digit value, 0-10)
 */

static unsigned
weight_checkdig(char *isn, unsigned size)
{
 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;
}


/*
 * checkdig --- Receives a buffer with a normalized ISxN string number,
 *     and the length to check.
 *
 * Returns the check digit value (0-9)
 */

static unsigned
checkdig(char *num, unsigned size)
{
 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;
}

/*
 * ean2isn --- Try to convert an ean13 number to a UPC/ISxN number.
 *      This doesn't verify for a valid check digit.
 *
 * 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)
{
 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;
}

/*
 * 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
ean2ISBN(char *isn)
{
 char    *aux;
 unsigned check;

 /*
  * The number should come in this format: 978-0-000-00000-0 or may be an
  * ISBN-13 number, 979-..., which does not have a short representation. Do
  * the short output version if possible.
 */

 if (strncmp("978-", isn, 4) == 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 inline void
ean2ISMN(char *isn)
{
 /* the number should come in this format: 979-0-000-00000-0 */
 /* Just strip the first part and change the first digit ('0') to 'M' */
 hyphenate(isn, isn + 4, NULL, NULL);
 isn[0] = 'M';
}

static inline void
ean2ISSN(char *isn)
{
 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';
}

static inline void
ean2UPC(char *isn)
{
 /* the number should come in this format: 000-000000000-0 */
 /* Strip the first part, crop, and dehyphenate */
 dehyphenate(isn, isn + 1);
 isn[12] = '\0';
}

/*
 * ean2* --- Converts a string of digits into an ean13 number.
 *     Assumes the input string is a string with only digits
 *     on it, and that it's within the range of ean13.
 *
 * Returns the ean13 value of the string.
 */

static ean13
str2ean(const char *num)
{
 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 */
}

/*
 * ean2string --- Try to convert an ean13 number to a hyphenated string.
 *      Assumes there's enough space in result to hold
 *      the string (maximum MAXEAN13LEN+1 bytes)
 *      This doesn't verify for a valid check digit.
 *
 * If shortType is true, the returned string is in the old ISxN short format.
 * 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
ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
{
 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;
}

/*
 * string2ean --- try to parse a string into an ean13.
 *
 * ereturn false with a useful error message if the string is bad.
 * Otherwise return true.
 *
 * 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, struct Node *escontext, ean13 *result,
     enum isn_type accept)
{
 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 suffix 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:
   memcpy(buf, "9790", 4); /* this isn't for sure yet, for now ISMN
 * it's only 9790 */

   valid = (valid && ((rcheck = checkdig(buf, 13)) == check || magic));
   break;
  case ISBN:
   memcpy(buf, "978", 3);
   valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
   break;
  case ISSN:
   memcpy(buf + 10, "00", 2); /* append 00 as the normal issue
 * publication code */

   memcpy(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 (rcheck == (unsigned) -1)
 {
  ereturn(escontext, false,
    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     errmsg("invalid %s number: \"%s\"",
      isn_names[accept], str)));
 }
 else
 {
  ereturn(escontext, false,
    (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'))));
 }

eaninvalid:
 ereturn(escontext, false,
   (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    errmsg("invalid input syntax for %s number: \"%s\"",
     isn_names[accept], str)));

eanwrongtype:
 ereturn(escontext, false,
   (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    errmsg("cannot cast %s to %s for number: \"%s\"",
     isn_names[type], isn_names[accept], str)));

eantoobig:
 ereturn(escontext, false,
   (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    errmsg("value \"%s\" is out of range for %s type",
     str, isn_names[accept])));
}

/*----------------------------------------------------------
 * Exported routines.
 *---------------------------------------------------------*/


void
_PG_init(void)
{
 if (ISN_DEBUG)
 {
  if (!check_table(EAN13_range, EAN13_index))
   elog(ERROR, "EAN13 failed check");
  if (!check_table(ISBN_range, ISBN_index))
   elog(ERROR, "ISBN failed check");
  if (!check_table(ISMN_range, ISMN_index))
   elog(ERROR, "ISMN failed check");
  if (!check_table(ISSN_range, ISSN_index))
   elog(ERROR, "ISSN failed check");
  if (!check_table(UPC_range, UPC_index))
   elog(ERROR, "UPC failed check");
 }

 /* Define a GUC variable for weak mode. */
 DefineCustomBoolVariable("isn.weak",
        "Accept input with invalid ISN check digits.",
        NULL,
        &g_weak,
        false,
        PGC_USERSET,
        0,
        NULL,
        NULL,
        NULL);

 MarkGUCPrefixReserved("isn");
}

/* isn_out
 */

PG_FUNCTION_INFO_V1(isn_out);
Datum
isn_out(PG_FUNCTION_ARGS)
{
 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);
}

/* ean13_out
 */

PG_FUNCTION_INFO_V1(ean13_out);
Datum
ean13_out(PG_FUNCTION_ARGS)
{
 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);
}

/* ean13_in
 */

PG_FUNCTION_INFO_V1(ean13_in);
Datum
ean13_in(PG_FUNCTION_ARGS)
{
 const char *str = PG_GETARG_CSTRING(0);
 ean13  result;

 if (!string2ean(str, fcinfo->context, &result, EAN13))
  PG_RETURN_NULL();
 PG_RETURN_EAN13(result);
}

/* isbn_in
 */

PG_FUNCTION_INFO_V1(isbn_in);
Datum
isbn_in(PG_FUNCTION_ARGS)
{
 const char *str = PG_GETARG_CSTRING(0);
 ean13  result;

 if (!string2ean(str, fcinfo->context, &result, ISBN))
  PG_RETURN_NULL();
 PG_RETURN_EAN13(result);
}

/* ismn_in
 */

PG_FUNCTION_INFO_V1(ismn_in);
Datum
ismn_in(PG_FUNCTION_ARGS)
{
 const char *str = PG_GETARG_CSTRING(0);
 ean13  result;

 if (!string2ean(str, fcinfo->context, &result, ISMN))
  PG_RETURN_NULL();
 PG_RETURN_EAN13(result);
}

/* issn_in
 */

PG_FUNCTION_INFO_V1(issn_in);
Datum
issn_in(PG_FUNCTION_ARGS)
{
 const char *str = PG_GETARG_CSTRING(0);
 ean13  result;

 if (!string2ean(str, fcinfo->context, &result, ISSN))
  PG_RETURN_NULL();
 PG_RETURN_EAN13(result);
}

/* upc_in
 */

PG_FUNCTION_INFO_V1(upc_in);
Datum
upc_in(PG_FUNCTION_ARGS)
{
 const char *str = PG_GETARG_CSTRING(0);
 ean13  result;

 if (!string2ean(str, fcinfo->context, &result, UPC))
  PG_RETURN_NULL();
 PG_RETURN_EAN13(result);
}

/* casting functions
*/

PG_FUNCTION_INFO_V1(isbn_cast_from_ean13);
Datum
isbn_cast_from_ean13(PG_FUNCTION_ARGS)
{
 ean13  val = PG_GETARG_EAN13(0);
 ean13  result;

 (void) ean2isn(val, false, &result, ISBN);

 PG_RETURN_EAN13(result);
}

PG_FUNCTION_INFO_V1(ismn_cast_from_ean13);
Datum
ismn_cast_from_ean13(PG_FUNCTION_ARGS)
{
 ean13  val = PG_GETARG_EAN13(0);
 ean13  result;

 (void) ean2isn(val, false, &result, ISMN);

 PG_RETURN_EAN13(result);
}

PG_FUNCTION_INFO_V1(issn_cast_from_ean13);
Datum
issn_cast_from_ean13(PG_FUNCTION_ARGS)
{
 ean13  val = PG_GETARG_EAN13(0);
 ean13  result;

 (void) ean2isn(val, false, &result, ISSN);

 PG_RETURN_EAN13(result);
}

PG_FUNCTION_INFO_V1(upc_cast_from_ean13);
Datum
upc_cast_from_ean13(PG_FUNCTION_ARGS)
{
 ean13  val = PG_GETARG_EAN13(0);
 ean13  result;

 (void) ean2isn(val, 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);
Datum
is_valid(PG_FUNCTION_ARGS)
{
 ean13  val = PG_GETARG_EAN13(0);

 PG_RETURN_BOOL((val & 1) == 0);
}

/* make_valid - unsets the "invalid-check-digit-on-input" flag
 */

PG_FUNCTION_INFO_V1(make_valid);
Datum
make_valid(PG_FUNCTION_ARGS)
{
 ean13  val = PG_GETARG_EAN13(0);

 val &= ~((ean13) 1);
 PG_RETURN_EAN13(val);
}

/* this function temporarily sets weak input flag
 * (to lose the strictness of check digit acceptance)
 */

PG_FUNCTION_INFO_V1(accept_weak_input);
Datum
accept_weak_input(PG_FUNCTION_ARGS)
{
 bool  newvalue = PG_GETARG_BOOL(0);

 (void) set_config_option("isn.weak", newvalue ? "on" : "off",
        PGC_USERSET, PGC_S_SESSION,
        GUC_ACTION_SET, true, 0, false);
 PG_RETURN_BOOL(g_weak);
}

PG_FUNCTION_INFO_V1(weak_input_status);
Datum
weak_input_status(PG_FUNCTION_ARGS)
{
 PG_RETURN_BOOL(g_weak);
}

Messung V0.5 in Prozent
C=84 H=87 G=85

¤ Dauer der Verarbeitung: 0.8 Sekunden  (vorverarbeitet am  2026-09-27) ¤

*© Formatika GbR, Deutschland






Versionsinformation zu Columbo

Bemerkung:

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126438
#Domains=1867298