00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "fmgr.h"
00018 #include "utils/builtins.h"
00019
00020 #include "isn.h"
00021 #include "EAN13.h"
00022 #include "ISBN.h"
00023 #include "ISMN.h"
00024 #include "ISSN.h"
00025 #include "UPC.h"
00026
00027 PG_MODULE_MAGIC;
00028
00029 #define MAXEAN13LEN 18
00030
00031 enum isn_type
00032 {
00033 INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC
00034 };
00035
00036 static const char *const isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC"};
00037
00038 static bool g_weak = false;
00039 static bool g_initialized = false;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #ifdef ISN_DEBUG
00060 static bool
00061 check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
00062 {
00063 const char *aux1,
00064 *aux2;
00065 int a,
00066 b,
00067 x = 0,
00068 y = -1,
00069 i = 0,
00070 j,
00071 cnt = 0,
00072 init = 0;
00073
00074 if (TABLE == NULL || TABLE_index == NULL)
00075 return true;
00076
00077 while (TABLE[i][0] && TABLE[i][1])
00078 {
00079 aux1 = TABLE[i][0];
00080 aux2 = TABLE[i][1];
00081
00082
00083 if (!isdigit((unsigned char) *aux1) || !isdigit((unsigned char) *aux2))
00084 goto invalidtable;
00085 a = *aux1 - '0';
00086 b = *aux2 - '0';
00087
00088
00089 while (*aux1 && *aux2)
00090 {
00091 if (!(isdigit((unsigned char) *aux1) &&
00092 isdigit((unsigned char) *aux2)) &&
00093 (*aux1 != *aux2 || *aux1 != '-'))
00094 goto invalidtable;
00095 aux1++;
00096 aux2++;
00097 }
00098 if (*aux1 != *aux2)
00099 goto invalidtable;
00100
00101
00102 if (a > y)
00103 {
00104
00105 for (j = x; j <= y; j++)
00106 {
00107 if (TABLE_index[j][0] != init)
00108 goto invalidindex;
00109 if (TABLE_index[j][1] != i - init)
00110 goto invalidindex;
00111 }
00112 init = i;
00113 x = a;
00114 }
00115
00116
00117 y = b;
00118 if (y < x)
00119 goto invalidtable;
00120 i++;
00121 }
00122
00123 return true;
00124
00125 invalidtable:
00126 elog(DEBUG1, "invalid table near {\"%s\", \"%s\"} (pos: %d)",
00127 TABLE[i][0], TABLE[i][1], i);
00128 return false;
00129
00130 invalidindex:
00131 elog(DEBUG1, "index %d is invalid", j);
00132 return false;
00133 }
00134 #endif
00135
00136
00137
00138
00139
00140 static unsigned
00141 dehyphenate(char *bufO, char *bufI)
00142 {
00143 unsigned ret = 0;
00144
00145 while (*bufI)
00146 {
00147 if (isdigit((unsigned char) *bufI))
00148 {
00149 *bufO++ = *bufI;
00150 ret++;
00151 }
00152 bufI++;
00153 }
00154 *bufO = '\0';
00155 return ret;
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165 static unsigned
00166 hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
00167 {
00168 unsigned ret = 0;
00169 const char *ean_aux1,
00170 *ean_aux2,
00171 *ean_p;
00172 char *firstdig,
00173 *aux1,
00174 *aux2;
00175 unsigned search,
00176 upper,
00177 lower,
00178 step;
00179 bool ean_in1,
00180 ean_in2;
00181
00182
00183 if (TABLE == NULL || TABLE_index == NULL)
00184 {
00185 while (*bufI)
00186 {
00187 *bufO++ = *bufI++;
00188 ret++;
00189 }
00190 *bufO = '\0';
00191 return (ret + 1);
00192 }
00193
00194
00195
00196 search = *bufI - '0';
00197 upper = lower = TABLE_index[search][0];
00198 upper += TABLE_index[search][1];
00199 lower--;
00200
00201 step = (upper - lower) / 2;
00202 if (step == 0)
00203 return 0;
00204 search = lower + step;
00205
00206 firstdig = bufI;
00207 ean_in1 = ean_in2 = false;
00208 ean_aux1 = TABLE[search][0];
00209 ean_aux2 = TABLE[search][1];
00210 do
00211 {
00212 if ((ean_in1 || *firstdig >= *ean_aux1) && (ean_in2 || *firstdig <= *ean_aux2))
00213 {
00214 if (*firstdig > *ean_aux1)
00215 ean_in1 = true;
00216 if (*firstdig < *ean_aux2)
00217 ean_in2 = true;
00218 if (ean_in1 && ean_in2)
00219 break;
00220
00221 firstdig++, ean_aux1++, ean_aux2++;
00222 if (!(*ean_aux1 && *ean_aux2 && *firstdig))
00223 break;
00224 if (!isdigit((unsigned char) *ean_aux1))
00225 ean_aux1++, ean_aux2++;
00226 }
00227 else
00228 {
00229
00230
00231
00232
00233 if (*firstdig < *ean_aux1 && !ean_in1)
00234 upper = search;
00235 else
00236 lower = search;
00237
00238 step = (upper - lower) / 2;
00239 search = lower + step;
00240
00241
00242 firstdig = bufI;
00243 ean_in1 = ean_in2 = false;
00244 ean_aux1 = TABLE[search][0];
00245 ean_aux2 = TABLE[search][1];
00246 }
00247 } while (step);
00248
00249 if (step)
00250 {
00251 aux1 = bufO;
00252 aux2 = bufI;
00253 ean_p = TABLE[search][0];
00254 while (*ean_p && *aux2)
00255 {
00256 if (*ean_p++ != '-')
00257 *aux1++ = *aux2++;
00258 else
00259 *aux1++ = '-';
00260 ret++;
00261 }
00262 *aux1++ = '-';
00263 *aux1 = *aux2;
00264 return (ret + 1);
00265 }
00266 return ret;
00267 }
00268
00269
00270
00271
00272
00273
00274
00275 static unsigned
00276 weight_checkdig(char *isn, unsigned size)
00277 {
00278 unsigned weight = 0;
00279
00280 while (*isn && size > 1)
00281 {
00282 if (isdigit((unsigned char) *isn))
00283 {
00284 weight += size-- * (*isn - '0');
00285 }
00286 isn++;
00287 }
00288 weight = weight % 11;
00289 if (weight != 0)
00290 weight = 11 - weight;
00291 return weight;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301 static unsigned
00302 checkdig(char *num, unsigned size)
00303 {
00304 unsigned check = 0,
00305 check3 = 0;
00306 unsigned pos = 0;
00307
00308 if (*num == 'M')
00309 {
00310 check3 = 3;
00311 pos = 1;
00312 }
00313 while (*num && size > 1)
00314 {
00315 if (isdigit((unsigned char) *num))
00316 {
00317 if (pos++ % 2)
00318 check3 += *num - '0';
00319 else
00320 check += *num - '0';
00321 size--;
00322 }
00323 num++;
00324 }
00325 check = (check + 3 * check3) % 10;
00326 if (check != 0)
00327 check = 10 - check;
00328 return check;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338 static bool
00339 ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)
00340 {
00341 enum isn_type type = INVALID;
00342
00343 char buf[MAXEAN13LEN + 1];
00344 char *aux;
00345 unsigned digval;
00346 unsigned search;
00347 ean13 ret = ean;
00348
00349 ean >>= 1;
00350
00351 if (ean > UINT64CONST(9999999999999))
00352 goto eantoobig;
00353
00354
00355 search = 0;
00356 aux = buf + 13;
00357 *aux = '\0';
00358 do
00359 {
00360 digval = (unsigned) (ean % 10);
00361 ean /= 10;
00362 *--aux = (char) (digval + '0');
00363 } while (ean && search++ < 12);
00364 while (search++ < 12)
00365 *--aux = '0';
00366
00367
00368 if (strncmp("978", buf, 3) == 0)
00369 {
00370 type = ISBN;
00371 }
00372 else if (strncmp("977", buf, 3) == 0)
00373 {
00374 type = ISSN;
00375 }
00376 else if (strncmp("9790", buf, 4) == 0)
00377 {
00378 type = ISMN;
00379 }
00380 else if (strncmp("979", buf, 3) == 0)
00381 {
00382 type = ISBN;
00383 }
00384 else if (*buf == '0')
00385 {
00386 type = UPC;
00387 }
00388 else
00389 {
00390 type = EAN13;
00391 }
00392 if (accept != ANY && accept != EAN13 && accept != type)
00393 goto eanwrongtype;
00394
00395 *result = ret;
00396 return true;
00397
00398 eanwrongtype:
00399 if (!errorOK)
00400 {
00401 if (type != EAN13)
00402 {
00403 ereport(ERROR,
00404 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00405 errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",
00406 isn_names[type], isn_names[accept], buf)));
00407 }
00408 else
00409 {
00410 ereport(ERROR,
00411 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00412 errmsg("cannot cast %s to %s for number: \"%s\"",
00413 isn_names[type], isn_names[accept], buf)));
00414 }
00415 }
00416 return false;
00417
00418 eantoobig:
00419 if (!errorOK)
00420 {
00421 char eanbuf[64];
00422
00423
00424
00425
00426
00427 snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
00428 ereport(ERROR,
00429 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00430 errmsg("value \"%s\" is out of range for %s type",
00431 eanbuf, isn_names[type])));
00432 }
00433 return false;
00434 }
00435
00436
00437
00438
00439
00440 static inline void
00441 ean2ISBN(char *isn)
00442 {
00443 char *aux;
00444 unsigned check;
00445
00446
00447
00448 hyphenate(isn, isn + 4, NULL, NULL);
00449 check = weight_checkdig(isn, 10);
00450 aux = strchr(isn, '\0');
00451 while (!isdigit((unsigned char) *--aux));
00452 if (check == 10)
00453 *aux = 'X';
00454 else
00455 *aux = check + '0';
00456 }
00457
00458 static inline void
00459 ean2ISMN(char *isn)
00460 {
00461
00462
00463 hyphenate(isn, isn + 4, NULL, NULL);
00464 isn[0] = 'M';
00465 }
00466
00467 static inline void
00468 ean2ISSN(char *isn)
00469 {
00470 unsigned check;
00471
00472
00473
00474 hyphenate(isn, isn + 4, NULL, NULL);
00475 check = weight_checkdig(isn, 8);
00476 if (check == 10)
00477 isn[8] = 'X';
00478 else
00479 isn[8] = check + '0';
00480 isn[9] = '\0';
00481 }
00482
00483 static inline void
00484 ean2UPC(char *isn)
00485 {
00486
00487
00488 dehyphenate(isn, isn + 1);
00489 isn[12] = '\0';
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499 static ean13
00500 str2ean(const char *num)
00501 {
00502 ean13 ean = 0;
00503
00504 while (*num)
00505 {
00506 if (isdigit((unsigned char) *num))
00507 ean = 10 * ean + (*num - '0');
00508 num++;
00509 }
00510 return (ean << 1);
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 static bool
00524 ean2string(ean13 ean, bool errorOK, char *result, bool shortType)
00525 {
00526 const char *(*TABLE)[2];
00527 const unsigned (*TABLE_index)[2];
00528 enum isn_type type = INVALID;
00529
00530 char *aux;
00531 unsigned digval;
00532 unsigned search;
00533 char valid = '\0';
00534
00535
00536 TABLE_index = ISBN_index;
00537
00538 if ((ean & 1) != 0)
00539 valid = '!';
00540 ean >>= 1;
00541
00542 if (ean > UINT64CONST(9999999999999))
00543 goto eantoobig;
00544
00545
00546 search = 0;
00547 aux = result + MAXEAN13LEN;
00548 *aux = '\0';
00549 *--aux = valid;
00550
00551 do
00552 {
00553 digval = (unsigned) (ean % 10);
00554 ean /= 10;
00555 *--aux = (char) (digval + '0');
00556 if (search == 0)
00557 *--aux = '-';
00558 } while (ean && search++ < 13);
00559 while (search++ < 13)
00560 *--aux = '0';
00561
00562
00563 search = hyphenate(result, result + 3, EAN13_range, EAN13_index);
00564
00565
00566 if (search == 0)
00567 {
00568 search = hyphenate(result, result + 3, NULL, NULL);
00569 goto okay;
00570 }
00571
00572
00573 if (strncmp("978-", result, search) == 0)
00574 {
00575
00576 type = ISBN;
00577 TABLE = ISBN_range;
00578 TABLE_index = ISBN_index;
00579 }
00580 else if (strncmp("977-", result, search) == 0)
00581 {
00582
00583 type = ISSN;
00584 TABLE = ISSN_range;
00585 TABLE_index = ISSN_index;
00586 }
00587 else if (strncmp("979-0", result, search + 1) == 0)
00588 {
00589
00590 type = ISMN;
00591 TABLE = ISMN_range;
00592 TABLE_index = ISMN_index;
00593 }
00594 else if (strncmp("979-", result, search) == 0)
00595 {
00596
00597 type = ISBN;
00598 TABLE = ISBN_range_new;
00599 TABLE_index = ISBN_index_new;
00600 }
00601 else if (*result == '0')
00602 {
00603
00604 type = UPC;
00605 TABLE = UPC_range;
00606 TABLE_index = UPC_index;
00607 }
00608 else
00609 {
00610 type = EAN13;
00611 TABLE = NULL;
00612 TABLE_index = NULL;
00613 }
00614
00615
00616 digval = search;
00617 search = hyphenate(result + digval, result + digval + 2, TABLE, TABLE_index);
00618
00619
00620 if (search == 0)
00621 {
00622 search = hyphenate(result + digval, result + digval + 2, NULL, NULL);
00623 goto okay;
00624 }
00625
00626 okay:
00627
00628 if (shortType)
00629 switch (type)
00630 {
00631 case ISBN:
00632 ean2ISBN(result);
00633 break;
00634 case ISMN:
00635 ean2ISMN(result);
00636 break;
00637 case ISSN:
00638 ean2ISSN(result);
00639 break;
00640 case UPC:
00641 ean2UPC(result);
00642 break;
00643 default:
00644 break;
00645 }
00646 return true;
00647
00648 eantoobig:
00649 if (!errorOK)
00650 {
00651 char eanbuf[64];
00652
00653
00654
00655
00656
00657 snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean);
00658 ereport(ERROR,
00659 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00660 errmsg("value \"%s\" is out of range for %s type",
00661 eanbuf, isn_names[type])));
00662 }
00663 return false;
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675 static bool
00676 string2ean(const char *str, bool errorOK, ean13 *result,
00677 enum isn_type accept)
00678 {
00679 bool digit,
00680 last;
00681 char buf[17] = " ";
00682 char *aux1 = buf + 3;
00683
00684 const char *aux2 = str;
00685 enum isn_type type = INVALID;
00686 unsigned check = 0,
00687 rcheck = (unsigned) -1;
00688 unsigned length = 0;
00689 bool magic = false,
00690 valid = true;
00691
00692
00693 while (*aux2 && length <= 13)
00694 {
00695 last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0');
00696 digit = (isdigit((unsigned char) *aux2) != 0);
00697
00698 if (*aux2 == '?' && last)
00699
00700 magic = digit = true;
00701 if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))
00702 {
00703
00704 if (type != INVALID)
00705 goto eaninvalid;
00706 type = ISMN;
00707 *aux1++ = 'M';
00708 length++;
00709 }
00710 else if (length == 7 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
00711 {
00712
00713 if (type != INVALID)
00714 goto eaninvalid;
00715 type = ISSN;
00716 *aux1++ = toupper((unsigned char) *aux2);
00717 length++;
00718 }
00719 else if (length == 9 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
00720 {
00721
00722 if (type != INVALID && type != ISMN)
00723 goto eaninvalid;
00724 if (type == INVALID)
00725 type = ISBN;
00726 *aux1++ = toupper((unsigned char) *aux2);
00727 length++;
00728 }
00729 else if (length == 11 && digit && last)
00730 {
00731
00732 if (type != INVALID)
00733 goto eaninvalid;
00734 type = UPC;
00735 *aux1++ = *aux2;
00736 length++;
00737 }
00738 else if (*aux2 == '-' || *aux2 == ' ')
00739 {
00740
00741 }
00742 else if (*aux2 == '!' && *(aux2 + 1) == '\0')
00743 {
00744
00745 if (!magic)
00746 valid = false;
00747 magic = true;
00748 }
00749 else if (!digit)
00750 {
00751 goto eaninvalid;
00752 }
00753 else
00754 {
00755 *aux1++ = *aux2;
00756 if (++length > 13)
00757 goto eantoobig;
00758 }
00759 aux2++;
00760 }
00761 *aux1 = '\0';
00762
00763
00764 if (length == 13)
00765 {
00766
00767 if (type != INVALID)
00768 goto eaninvalid;
00769 type = EAN13;
00770 check = buf[15] - '0';
00771 }
00772 else if (length == 12)
00773 {
00774
00775 if (type != UPC)
00776 goto eaninvalid;
00777 check = buf[14] - '0';
00778 }
00779 else if (length == 10)
00780 {
00781 if (type != ISBN && type != ISMN)
00782 goto eaninvalid;
00783 if (buf[12] == 'X')
00784 check = 10;
00785 else
00786 check = buf[12] - '0';
00787 }
00788 else if (length == 8)
00789 {
00790 if (type != INVALID && type != ISSN)
00791 goto eaninvalid;
00792 type = ISSN;
00793 if (buf[10] == 'X')
00794 check = 10;
00795 else
00796 check = buf[10] - '0';
00797 }
00798 else
00799 goto eaninvalid;
00800
00801 if (type == INVALID)
00802 goto eaninvalid;
00803
00804
00805 if (accept == EAN13 && type != accept)
00806 goto eanwrongtype;
00807 if (accept != ANY && type != EAN13 && type != accept)
00808 goto eanwrongtype;
00809 switch (type)
00810 {
00811 case EAN13:
00812 valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));
00813
00814 if (buf[3] == '0')
00815 type = UPC;
00816 else if (strncmp("977", buf + 3, 3) == 0)
00817 type = ISSN;
00818 else if (strncmp("978", buf + 3, 3) == 0)
00819 type = ISBN;
00820 else if (strncmp("9790", buf + 3, 4) == 0)
00821 type = ISMN;
00822 else if (strncmp("979", buf + 3, 3) == 0)
00823 type = ISBN;
00824 if (accept != EAN13 && accept != ANY && type != accept)
00825 goto eanwrongtype;
00826 break;
00827 case ISMN:
00828 strncpy(buf, "9790", 4);
00829
00830 valid = (valid && ((rcheck = checkdig(buf + 3, 10)) == check || magic));
00831 break;
00832 case ISBN:
00833 strncpy(buf, "978", 3);
00834 valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
00835 break;
00836 case ISSN:
00837 strncpy(buf + 10, "00", 2);
00838
00839 strncpy(buf, "977", 3);
00840 valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));
00841 break;
00842 case UPC:
00843 buf[2] = '0';
00844 valid = (valid && ((rcheck = checkdig(buf + 2, 13)) == check || magic));
00845 default:
00846 break;
00847 }
00848
00849
00850 for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
00851 aux1[12] = checkdig(aux1, 13) + '0';
00852 aux1[13] = '\0';
00853
00854 if (!valid && !magic)
00855 goto eanbadcheck;
00856
00857 *result = str2ean(aux1);
00858 *result |= valid ? 0 : 1;
00859 return true;
00860
00861 eanbadcheck:
00862 if (g_weak)
00863 {
00864
00865 *result = str2ean(aux1);
00866 *result |= 1;
00867 return true;
00868 }
00869
00870 if (!errorOK)
00871 {
00872 if (rcheck == (unsigned) -1)
00873 {
00874 ereport(ERROR,
00875 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00876 errmsg("invalid %s number: \"%s\"",
00877 isn_names[accept], str)));
00878 }
00879 else
00880 {
00881 ereport(ERROR,
00882 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00883 errmsg("invalid check digit for %s number: \"%s\", should be %c",
00884 isn_names[accept], str, (rcheck == 10) ? ('X') : (rcheck + '0'))));
00885 }
00886 }
00887 return false;
00888
00889 eaninvalid:
00890 if (!errorOK)
00891 ereport(ERROR,
00892 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00893 errmsg("invalid input syntax for %s number: \"%s\"",
00894 isn_names[accept], str)));
00895 return false;
00896
00897 eanwrongtype:
00898 if (!errorOK)
00899 ereport(ERROR,
00900 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00901 errmsg("cannot cast %s to %s for number: \"%s\"",
00902 isn_names[type], isn_names[accept], str)));
00903 return false;
00904
00905 eantoobig:
00906 if (!errorOK)
00907 ereport(ERROR,
00908 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00909 errmsg("value \"%s\" is out of range for %s type",
00910 str, isn_names[accept])));
00911 return false;
00912 }
00913
00914
00915
00916
00917
00918 void
00919 initialize(void)
00920 {
00921 #ifdef ISN_DEBUG
00922 if (!check_table(EAN13, EAN13_index))
00923 elog(LOG, "EAN13 failed check");
00924 if (!check_table(ISBN, ISBN_index))
00925 elog(LOG, "ISBN failed check");
00926 if (!check_table(ISMN, ISMN_index))
00927 elog(LOG, "ISMN failed check");
00928 if (!check_table(ISSN, ISSN_index))
00929 elog(LOG, "ISSN failed check");
00930 if (!check_table(UPC, UPC_index))
00931 elog(LOG, "UPC failed check");
00932 #endif
00933 g_initialized = true;
00934 }
00935
00936
00937
00938 PG_FUNCTION_INFO_V1(isn_out);
00939 Datum
00940 isn_out(PG_FUNCTION_ARGS)
00941 {
00942 ean13 val = PG_GETARG_EAN13(0);
00943 char *result;
00944 char buf[MAXEAN13LEN + 1];
00945
00946 (void) ean2string(val, false, buf, true);
00947
00948 result = pstrdup(buf);
00949 PG_RETURN_CSTRING(result);
00950 }
00951
00952
00953
00954 PG_FUNCTION_INFO_V1(ean13_out);
00955 Datum
00956 ean13_out(PG_FUNCTION_ARGS)
00957 {
00958 ean13 val = PG_GETARG_EAN13(0);
00959 char *result;
00960 char buf[MAXEAN13LEN + 1];
00961
00962 (void) ean2string(val, false, buf, false);
00963
00964 result = pstrdup(buf);
00965 PG_RETURN_CSTRING(result);
00966 }
00967
00968
00969
00970 PG_FUNCTION_INFO_V1(ean13_in);
00971 Datum
00972 ean13_in(PG_FUNCTION_ARGS)
00973 {
00974 const char *str = PG_GETARG_CSTRING(0);
00975 ean13 result;
00976
00977 (void) string2ean(str, false, &result, EAN13);
00978 PG_RETURN_EAN13(result);
00979 }
00980
00981
00982
00983 PG_FUNCTION_INFO_V1(isbn_in);
00984 Datum
00985 isbn_in(PG_FUNCTION_ARGS)
00986 {
00987 const char *str = PG_GETARG_CSTRING(0);
00988 ean13 result;
00989
00990 (void) string2ean(str, false, &result, ISBN);
00991 PG_RETURN_EAN13(result);
00992 }
00993
00994
00995
00996 PG_FUNCTION_INFO_V1(ismn_in);
00997 Datum
00998 ismn_in(PG_FUNCTION_ARGS)
00999 {
01000 const char *str = PG_GETARG_CSTRING(0);
01001 ean13 result;
01002
01003 (void) string2ean(str, false, &result, ISMN);
01004 PG_RETURN_EAN13(result);
01005 }
01006
01007
01008
01009 PG_FUNCTION_INFO_V1(issn_in);
01010 Datum
01011 issn_in(PG_FUNCTION_ARGS)
01012 {
01013 const char *str = PG_GETARG_CSTRING(0);
01014 ean13 result;
01015
01016 (void) string2ean(str, false, &result, ISSN);
01017 PG_RETURN_EAN13(result);
01018 }
01019
01020
01021
01022 PG_FUNCTION_INFO_V1(upc_in);
01023 Datum
01024 upc_in(PG_FUNCTION_ARGS)
01025 {
01026 const char *str = PG_GETARG_CSTRING(0);
01027 ean13 result;
01028
01029 (void) string2ean(str, false, &result, UPC);
01030 PG_RETURN_EAN13(result);
01031 }
01032
01033
01034
01035 PG_FUNCTION_INFO_V1(isbn_cast_from_ean13);
01036 Datum
01037 isbn_cast_from_ean13(PG_FUNCTION_ARGS)
01038 {
01039 ean13 val = PG_GETARG_EAN13(0);
01040 ean13 result;
01041
01042 (void) ean2isn(val, false, &result, ISBN);
01043
01044 PG_RETURN_EAN13(result);
01045 }
01046
01047 PG_FUNCTION_INFO_V1(ismn_cast_from_ean13);
01048 Datum
01049 ismn_cast_from_ean13(PG_FUNCTION_ARGS)
01050 {
01051 ean13 val = PG_GETARG_EAN13(0);
01052 ean13 result;
01053
01054 (void) ean2isn(val, false, &result, ISMN);
01055
01056 PG_RETURN_EAN13(result);
01057 }
01058
01059 PG_FUNCTION_INFO_V1(issn_cast_from_ean13);
01060 Datum
01061 issn_cast_from_ean13(PG_FUNCTION_ARGS)
01062 {
01063 ean13 val = PG_GETARG_EAN13(0);
01064 ean13 result;
01065
01066 (void) ean2isn(val, false, &result, ISSN);
01067
01068 PG_RETURN_EAN13(result);
01069 }
01070
01071 PG_FUNCTION_INFO_V1(upc_cast_from_ean13);
01072 Datum
01073 upc_cast_from_ean13(PG_FUNCTION_ARGS)
01074 {
01075 ean13 val = PG_GETARG_EAN13(0);
01076 ean13 result;
01077
01078 (void) ean2isn(val, false, &result, UPC);
01079
01080 PG_RETURN_EAN13(result);
01081 }
01082
01083
01084
01085
01086 PG_FUNCTION_INFO_V1(is_valid);
01087 Datum
01088 is_valid(PG_FUNCTION_ARGS)
01089 {
01090 ean13 val = PG_GETARG_EAN13(0);
01091
01092 PG_RETURN_BOOL((val & 1) == 0);
01093 }
01094
01095
01096
01097 PG_FUNCTION_INFO_V1(make_valid);
01098 Datum
01099 make_valid(PG_FUNCTION_ARGS)
01100 {
01101 ean13 val = PG_GETARG_EAN13(0);
01102
01103 val &= ~((ean13) 1);
01104 PG_RETURN_EAN13(val);
01105 }
01106
01107
01108
01109
01110
01111 PG_FUNCTION_INFO_V1(accept_weak_input);
01112 Datum
01113 accept_weak_input(PG_FUNCTION_ARGS)
01114 {
01115 #ifdef ISN_WEAK_MODE
01116 g_weak = PG_GETARG_BOOL(0);
01117 #else
01118
01119 #endif
01120 PG_RETURN_BOOL(g_weak);
01121 }
01122
01123 PG_FUNCTION_INFO_V1(weak_input_status);
01124 Datum
01125 weak_input_status(PG_FUNCTION_ARGS)
01126 {
01127 PG_RETURN_BOOL(g_weak);
01128 }