diff options
Diffstat (limited to 'contrib/isbn_issn/isbn_issn.c')
-rw-r--r-- | contrib/isbn_issn/isbn_issn.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/contrib/isbn_issn/isbn_issn.c b/contrib/isbn_issn/isbn_issn.c new file mode 100644 index 00000000000..a1d891d7bcf --- /dev/null +++ b/contrib/isbn_issn/isbn_issn.c @@ -0,0 +1,378 @@ +/* + * PostgreSQL type definitions for ISBNs. + * + * $Id: isbn_issn.c,v 1.1 2000/06/15 19:04:50 momjian Exp $ + */ + +#include <stdio.h> + +#include <postgres.h> +#include <utils/palloc.h> + +/* + * This is the internal storage format for ISBNs. + * NB: This is an intentional type pun with builtin type `char16'. + */ + +typedef struct isbn +{ + char num[13]; + char pad[3]; +} isbn; + +/* + * Various forward declarations: + */ + +isbn *isbn_in(char *str); +char *isbn_out(isbn * addr); + +bool isbn_lt(isbn * a1, isbn * a2); +bool isbn_le(isbn * a1, isbn * a2); +bool isbn_eq(isbn * a1, isbn * a2); +bool isbn_ge(isbn * a1, isbn * a2); +bool isbn_gt(isbn * a1, isbn * a2); + +bool isbn_ne(isbn * a1, isbn * a2); + +int4 isbn_cmp(isbn * a1, isbn * a2); + +int4 isbn_sum(char *str); + +/* + * ISBN reader. + */ + +isbn * +isbn_in(char *str) +{ + isbn *result; + + if (strlen(str) != 13) + { + elog(ERROR, "isbn_in: invalid ISBN \"%s\"", str); + return (NULL); + } + if (isbn_sum(str) != 0) + { + elog(ERROR, "isbn_in: purported ISBN \"%s\" failed checksum", + str); + return (NULL); + } + + result = (isbn *) palloc(sizeof(isbn)); + + strncpy(result->num, str, 13); + memset(result->pad, ' ', 3); + return (result); +} + +/* + * The ISBN checksum is defined as follows: + * + * Number the digits from 1 to 9 (call this N). + * Compute the sum, S, of N * D_N. + * The check digit, C, is the value which satisfies the equation + * S + 10*C === 0 (mod 11) + * The value 10 for C is written as `X'. + * + * For our purposes, we want the complete sum including the check + * digit; if this is zero, then the checksum passed. We also check + * the syntactic validity if the provided string, and return 12 + * if any errors are found. + */ +int4 +isbn_sum(char *str) +{ + int4 sum = 0, + dashes = 0, + val; + int i; + + for (i = 0; str[i] && i < 13; i++) + { + switch (str[i]) + { + case '-': + if (++dashes > 3) + return 12; + continue; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + val = str[i] - '0'; + break; + + case 'X': + case 'x': + val = 10; + break; + + default: + return 12; + } + + sum += val * (i + 1 - dashes); + } + return (sum % 11); +} + +/* + * ISBN output function. + */ + +char * +isbn_out(isbn * num) +{ + char *result; + + if (num == NULL) + return (NULL); + + result = (char *) palloc(14); + + result[0] = '\0'; + strncat(result, num->num, 13); + return (result); +} + +/* + * Boolean tests for magnitude. + */ + +bool +isbn_lt(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13) < 0); +}; + +bool +isbn_le(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13) <= 0); +}; + +bool +isbn_eq(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13) == 0); +}; + +bool +isbn_ge(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13) >= 0); +}; + +bool +isbn_gt(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13) > 0); +}; + +bool +isbn_ne(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13) != 0); +}; + +/* + * Comparison function for sorting: + */ + +int4 +isbn_cmp(isbn * a1, isbn * a2) +{ + return (strncmp(a1->num, a2->num, 13)); +} + + +/* ----------------------------- ISSN --------------------------- */ + +/* + * This is the internal storage format for ISSNs. + * NB: This is an intentional type pun with builtin type `char16'. + */ + +typedef struct issn +{ + char num[9]; + char pad[7]; +} issn; + +/* + * Various forward declarations: + */ + +issn *issn_in(char *str); +char *issn_out(issn * addr); + +bool issn_lt(issn * a1, issn * a2); +bool issn_le(issn * a1, issn * a2); +bool issn_eq(issn * a1, issn * a2); +bool issn_ge(issn * a1, issn * a2); +bool issn_gt(issn * a1, issn * a2); + +bool issn_ne(issn * a1, issn * a2); + +int4 issn_cmp(issn * a1, issn * a2); + +int4 issn_sum(char *str); + +/* + * ISSN reader. + */ + +issn * +issn_in(char *str) +{ + issn *result; + + if (strlen(str) != 9) + { + elog(ERROR, "issn_in: invalid ISSN \"%s\"", str); + return (NULL); + } + if (issn_sum(str) != 0) + { + elog(ERROR, "issn_in: purported ISSN \"%s\" failed checksum", + str); + return (NULL); + } + + result = (issn *) palloc(sizeof(issn)); + + strncpy(result->num, str, 9); + memset(result->pad, ' ', 7); + return (result); +} + +/* + * The ISSN checksum works just like the ISBN sum, only different + * (of course!). + * Here, the weights start at 8 and decrease. + */ +int4 +issn_sum(char *str) +{ + int4 sum = 0, + dashes = 0, + val; + int i; + + for (i = 0; str[i] && i < 9; i++) + { + switch (str[i]) + { + case '-': + if (++dashes > 1) + return 12; + continue; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + val = str[i] - '0'; + break; + + case 'X': + case 'x': + val = 10; + break; + + default: + return 12; + } + + sum += val * (8 - (i - dashes)); + } + return (sum % 11); +} + +/* + * ISSN output function. + */ + +char * +issn_out(issn * num) +{ + char *result; + + if (num == NULL) + return (NULL); + + result = (char *) palloc(14); + + result[0] = '\0'; + strncat(result, num->num, 9); + return (result); +} + +/* + * Boolean tests for magnitude. + */ + +bool +issn_lt(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9) < 0); +}; + +bool +issn_le(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9) <= 0); +}; + +bool +issn_eq(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9) == 0); +}; + +bool +issn_ge(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9) >= 0); +}; + +bool +issn_gt(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9) > 0); +}; + +bool +issn_ne(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9) != 0); +}; + +/* + * Comparison function for sorting: + */ + +int4 +issn_cmp(issn * a1, issn * a2) +{ + return (strncmp(a1->num, a2->num, 9)); +} + +/* + * eof + */ |