Skip to content

Commit 5e08e49

Browse files
committed
contrib/isn updates from Jeremy Kronuz.
1 parent f5b4d9a commit 5e08e49

File tree

4 files changed

+224
-73
lines changed

4 files changed

+224
-73
lines changed

contrib/isn/README.isn

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

2-
EAN13 - UPC - ISBN (books) - ISMN (music) - ISSN (serials)
3-
----------------------------------------------------------
2+
-- EAN13 - UPC - ISBN (books) - ISMN (music) - ISSN (serials)
3+
-------------------------------------------------------------
44

55
Copyright Germ�n M�ndez Bravo (Kronuz), 2004 - 2006
66
This module is released under the same BSD license as the rest of PostgreSQL.
@@ -24,7 +24,7 @@ THIS MODULE IS PROVIDED "AS IS" AND WITHOUT ANY WARRANTY
2424
OF ANY KIND, EXPRESS OR IMPLIED.
2525
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2626

27-
Content of the Module
27+
-- Content of the Module
2828
-------------------------------------------------
2929

3030
This directory contains definitions for a few PostgreSQL
@@ -143,7 +143,7 @@ On success:
143143

144144
(on failure, the functions 'ereport' the error)
145145

146-
Testing/Playing Functions
146+
-- Testing/Playing Functions
147147
-------------------------------------------------
148148
isn_weak(boolean) - Sets the weak input mode.
149149
This function is intended for testing use only!
@@ -173,17 +173,20 @@ To work with invalid numbers, you can use two functions:
173173
+ make_valid(), which validates an invalid number (deleting the invalid flag)
174174
+ is_valid(), which checks for the invalid flag presence.
175175

176-
Examples of Use
176+
-- Examples of Use
177177
-------------------------------------------------
178178
--Using the types directly:
179179
select isbn('978-0-393-04002-9');
180180
select isbn13('0901690546');
181181
select issn('1436-4522');
182182

183183
--Casting types:
184-
-- note that you can't cast from ean13 to other type, thus the following
185-
-- will NOT work: select upc(ean13('0220356483481'));
186-
select ean13(upc('220356483481'));
184+
-- note that you can only cast from ean13 to other type when the casted
185+
-- number would be valid in the realm of the casted type;
186+
-- thus, the following will NOT work: select isbn(ean13('0220356483481'));
187+
-- but these will:
188+
select upc(ean13('0220356483481'));
189+
select ean13(upc('220356483481'));
187190

188191
--Create a table with a single column to hold ISBN numbers:
189192
create table test ( id isbn );
@@ -210,7 +213,7 @@ Examples of Use
210213

211214
select isbn13(id) from test;
212215

213-
Contact
216+
-- Contact
214217
-------------------------------------------------
215218
Please suggestions or bug reports to kronuz at users.sourceforge.net
216219

contrib/isn/isn.c

Lines changed: 164 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.1 2006/09/09 04:07:52 tgl Exp $
10+
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.2 2006/09/10 20:45:17 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -31,7 +31,7 @@ PG_MODULE_MAGIC;
3131

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

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

3636
static bool g_weak = false;
3737
static bool g_initialized = false;
@@ -43,11 +43,11 @@ static bool g_initialized = false;
4343

4444
/***********************************************************************
4545
**
46-
** Routines for ISNs.
46+
** Routines for EAN13/UPC/ISxNs.
4747
**
4848
** Note:
4949
** In this code, a normalized string is one that is known to be a valid
50-
** ISN number containing only digits and hyphens and with enough space
50+
** ISxN number containing only digits and hyphens and with enough space
5151
** to hold the full 13 digits plus the maximum of four hyphens.
5252
***********************************************************************/
5353

@@ -217,7 +217,7 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
217217
}
218218

219219
/*
220-
* weight_checkdig -- Receives a buffer with a normalized ISN string number,
220+
* weight_checkdig -- Receives a buffer with a normalized ISxN string number,
221221
* and the length to weight.
222222
*
223223
* Returns the weight of the number (the check digit value, 0-10)
@@ -239,7 +239,7 @@ unsigned weight_checkdig(char *isn, unsigned size)
239239

240240

241241
/*
242-
* checkdig --- Receives a buffer with a normalized ISN string number,
242+
* checkdig --- Receives a buffer with a normalized ISxN string number,
243243
* and the length to check.
244244
*
245245
* Returns the check digit value (0-9)
@@ -267,8 +267,94 @@ unsigned checkdig(char *num, unsigned size)
267267
}
268268

269269
/*
270-
* ean2isn --- Convert in-place a normalized EAN13 string to the corresponding
271-
* ISN string number. Assumes the input string is normalized.
270+
* ean2isn --- Try to convert an ean13 number to a UPC/ISxN number.
271+
* This doesn't verify for a valid check digit.
272+
*
273+
* If errorOK is false, ereport a useful error message if the ean13 is bad.
274+
* If errorOK is true, just return "false" for bad input.
275+
*/
276+
static
277+
bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
278+
{
279+
enum isn_type type = INVALID;
280+
281+
char buf[MAXEAN13LEN + 1];
282+
char *firstdig, *aux;
283+
unsigned digval;
284+
unsigned search;
285+
ean13 ret = ean;
286+
287+
ean >>= 1;
288+
/* verify it's in the EAN13 range */
289+
if(ean > UINT64CONST(9999999999999))
290+
goto eantoobig;
291+
292+
/* convert the number */
293+
search = 0;
294+
firstdig = aux = buf + 13;
295+
*aux = '\0'; /* terminate string; aux points to last digit */
296+
do {
297+
digval = (unsigned)(ean % 10); /* get the decimal value */
298+
ean /= 10; /* get next digit */
299+
*--aux = (char)(digval + '0'); /* convert to ascii and store */
300+
} while(ean && search++<12);
301+
while(search++<12) *--aux = '0'; /* fill the remaining EAN13 with '0' */
302+
303+
/* find out the data type: */
304+
if(!strncmp("978", buf, 3)) { /* ISBN */
305+
type = ISBN;
306+
} else if(!strncmp("977", buf, 3)) { /* ISSN */
307+
type = ISSN;
308+
} else if(!strncmp("9790", buf, 4)) { /* ISMN */
309+
type = ISMN;
310+
} else if(!strncmp("979", buf, 3)) { /* ISBN-13 */
311+
type = ISBN;
312+
} else if(*buf == '0') { /* UPC */
313+
type = UPC;
314+
} else {
315+
type = EAN13;
316+
}
317+
if(accept != ANY && accept != EAN13 && accept != type) goto eanwrongtype;
318+
319+
*result = ret;
320+
return true;
321+
322+
eanwrongtype:
323+
if(!errorOK) {
324+
if(type!=EAN13) {
325+
ereport(ERROR,
326+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
327+
errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",
328+
isn_names[type], isn_names[accept], buf)));
329+
} else {
330+
ereport(ERROR,
331+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
332+
errmsg("cannot cast %s to %s for number: \"%s\"",
333+
isn_names[type], isn_names[accept], buf)));
334+
}
335+
}
336+
return false;
337+
338+
eantoobig:
339+
if(!errorOK) {
340+
char eanbuf[64];
341+
342+
/*
343+
* Format the number separately to keep the machine-dependent
344+
* format code out of the translatable message text
345+
*/
346+
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
347+
ereport(ERROR,
348+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
349+
errmsg("value \"%s\" is out of range for %s type",
350+
eanbuf, isn_names[type])));
351+
}
352+
return false;
353+
}
354+
355+
/*
356+
* ean2UPC/ISxN --- Convert in-place a normalized EAN13 string to the corresponding
357+
* UPC/ISxN string number. Assumes the input string is normalized.
272358
*/
273359
static inline
274360
void ean2ISBN(char *isn)
@@ -325,7 +411,8 @@ ean13 str2ean(const char *num)
325411
{
326412
ean13 ean = 0; /* current ean */
327413
while(*num) {
328-
ean = 10 * ean + ((*num++) - '0');
414+
if(isdigit(*num)) ean = 10 * ean + (*num - '0');
415+
num++;
329416
}
330417
return (ean<<1); /* also give room to a flag */
331418
}
@@ -336,7 +423,7 @@ ean13 str2ean(const char *num)
336423
* the string (maximum MAXEAN13LEN+1 bytes)
337424
* This doesn't verify for a valid check digit.
338425
*
339-
* If shortType is true, the returned string is in the old ISN short format.
426+
* If shortType is true, the returned string is in the old ISxN short format.
340427
* If errorOK is false, ereport a useful error message if the string is bad.
341428
* If errorOK is true, just return "false" for bad input.
342429
*/
@@ -369,8 +456,8 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
369456
digval = (unsigned)(ean % 10); /* get the decimal value */
370457
ean /= 10; /* get next digit */
371458
*--aux = (char)(digval + '0'); /* convert to ascii and store */
372-
if(++search == 1) *--aux = '-'; /* the check digit is always there */
373-
} while(ean);
459+
if(search == 0) *--aux = '-'; /* the check digit is always there */
460+
} while(ean && search++<13);
374461
while(search++<13) *--aux = '0'; /* fill the remaining EAN13 with '0' */
375462

376463
/* The string should be in this form: ???DDDDDDDDDDDD-D" */
@@ -409,7 +496,7 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
409496
TABLE_index = NULL;
410497
}
411498

412-
/* verify it's a logically valid EAN13/ISN */
499+
/* verify it's a logically valid EAN13/UPC/ISxN */
413500
digval = search;
414501
search = hyphenate(result+digval, result+digval+2, TABLE, TABLE_index);
415502

@@ -452,8 +539,8 @@ bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
452539
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
453540
ereport(ERROR,
454541
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
455-
errmsg("value \"%s\" is out of range for ISN type",
456-
eanbuf)));
542+
errmsg("value \"%s\" is out of range for %s type",
543+
eanbuf, isn_names[type])));
457544
}
458545
return false;
459546
}
@@ -483,7 +570,7 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
483570
/* recognize and validate the number: */
484571
while(*aux2 && length <= 13) {
485572
last = (*(aux2+1) == '!' || *(aux2+1) == '\0'); /* is the last character */
486-
digit = isdigit(*aux2); /* is current character a digit? */
573+
digit = (isdigit(*aux2)!=0); /* is current character a digit? */
487574
if(*aux2=='?' && last) /* automagically calculate check digit if it's '?' */
488575
magic = digit = true;
489576
if(length == 0 && (*aux2=='M' || *aux2=='m')) {
@@ -583,19 +670,25 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
583670
break;
584671
}
585672

586-
if(!valid && !magic) goto eanbadcheck;
587-
673+
/* fix the check digit: */
588674
for(aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
589675
aux1[12] = checkdig(aux1, 13) + '0';
590676
aux1[13] = '\0';
591677

678+
if(!valid && !magic) goto eanbadcheck;
679+
592680
*result = str2ean(aux1);
593681
*result |= valid?0:1;
594-
595682
return true;
596683

597684
eanbadcheck:
598-
if(!g_weak) {
685+
if(g_weak) { /* weak input mode is activated: */
686+
/* set the "invalid-check-digit-on-input" flag */
687+
*result = str2ean(aux1);
688+
*result |= 1;
689+
return true;
690+
}
691+
599692
if(!errorOK) {
600693
if(rcheck == (unsigned)-1) {
601694
ereport(ERROR,
@@ -610,30 +703,6 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
610703
}
611704
}
612705
return false;
613-
}
614-
615-
if(accept != EAN13 && accept != ANY && type != accept) goto eanwrongtype;
616-
617-
/* fix the check digit: */
618-
for(aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
619-
aux1[12] = checkdig(aux1, 13) + '0';
620-
aux1[13] = '\0';
621-
*result = str2ean(aux1);
622-
623-
/* set the "invalid-check-digit-on-input" flag */
624-
*result |= 1;
625-
626-
/* just warn about the error when there was a real check digit error: */
627-
if(check != rcheck) {
628-
if(rcheck == (unsigned)-1) {
629-
elog(WARNING, "invalid %s number: \"%s\"",
630-
isn_names[accept], str);
631-
} else {
632-
elog(WARNING, "invalid check digit for %s number: \"%s\", should be %c",
633-
isn_names[accept], str, (rcheck==10)?('X'):(rcheck+'0'));
634-
}
635-
}
636-
return true;
637706

638707
eaninvalid:
639708
if(!errorOK)
@@ -647,8 +716,8 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
647716
if(!errorOK)
648717
ereport(ERROR,
649718
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
650-
errmsg("invalid %s type for number: \"%s\"",
651-
isn_names[accept], str)));
719+
errmsg("cannot cast %s to %s for number: \"%s\"",
720+
isn_names[type], isn_names[accept], str)));
652721
return false;
653722

654723
eantoobig:
@@ -804,6 +873,55 @@ isn_cast_to_text(PG_FUNCTION_ARGS)
804873
PG_RETURN_TEXT_P(GET_TEXT(buf));
805874
}
806875

876+
PG_FUNCTION_INFO_V1(isbn_cast_from_ean13);
877+
Datum
878+
isbn_cast_from_ean13(PG_FUNCTION_ARGS)
879+
{
880+
ean13 val = PG_GETARG_EAN13(0);
881+
ean13 result;
882+
883+
(void) ean2isn(val, false, &result, ISBN);
884+
885+
PG_RETURN_EAN13(result);
886+
}
887+
888+
PG_FUNCTION_INFO_V1(ismn_cast_from_ean13);
889+
Datum
890+
ismn_cast_from_ean13(PG_FUNCTION_ARGS)
891+
{
892+
ean13 val = PG_GETARG_EAN13(0);
893+
ean13 result;
894+
895+
(void) ean2isn(val, false, &result, ISMN);
896+
897+
PG_RETURN_EAN13(result);
898+
}
899+
900+
PG_FUNCTION_INFO_V1(issn_cast_from_ean13);
901+
Datum
902+
issn_cast_from_ean13(PG_FUNCTION_ARGS)
903+
{
904+
ean13 val = PG_GETARG_EAN13(0);
905+
ean13 result;
906+
907+
(void) ean2isn(val, false, &result, ISSN);
908+
909+
PG_RETURN_EAN13(result);
910+
}
911+
912+
PG_FUNCTION_INFO_V1(upc_cast_from_ean13);
913+
Datum
914+
upc_cast_from_ean13(PG_FUNCTION_ARGS)
915+
{
916+
ean13 val = PG_GETARG_EAN13(0);
917+
ean13 result;
918+
919+
(void) ean2isn(val, false, &result, UPC);
920+
921+
PG_RETURN_EAN13(result);
922+
}
923+
924+
807925
PG_FUNCTION_INFO_V1(ean13_cast_from_text);
808926
Datum
809927
ean13_cast_from_text(PG_FUNCTION_ARGS)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy