|
| 1 | +/* |
| 2 | + * PostgreSQL type definitions for ISBNs. |
| 3 | + * |
| 4 | + * $Id: isbn.c,v 1.1 1998/08/17 03:35:04 scrappy Exp $ |
| 5 | + */ |
| 6 | + |
| 7 | +#include <stdio.h> |
| 8 | + |
| 9 | +#include <postgres.h> |
| 10 | +#include <utils/palloc.h> |
| 11 | + |
| 12 | +/* |
| 13 | + * This is the internal storage format for ISBNs. |
| 14 | + * NB: This is an intentional type pun with builtin type `char16'. |
| 15 | + */ |
| 16 | + |
| 17 | +typedef struct isbn |
| 18 | +{ |
| 19 | + char num[13]; |
| 20 | + char pad[3]; |
| 21 | +} isbn; |
| 22 | + |
| 23 | +/* |
| 24 | + * Various forward declarations: |
| 25 | + */ |
| 26 | + |
| 27 | +isbn *isbn_in(char *str); |
| 28 | +char *isbn_out(isbn * addr); |
| 29 | + |
| 30 | +bool isbn_lt(isbn * a1, isbn * a2); |
| 31 | +bool isbn_le(isbn * a1, isbn * a2); |
| 32 | +bool isbn_eq(isbn * a1, isbn * a2); |
| 33 | +bool isbn_ge(isbn * a1, isbn * a2); |
| 34 | +bool isbn_gt(isbn * a1, isbn * a2); |
| 35 | + |
| 36 | +bool isbn_ne(isbn * a1, isbn * a2); |
| 37 | + |
| 38 | +int4 isbn_cmp(isbn * a1, isbn * a2); |
| 39 | + |
| 40 | +int4 isbn_sum(char *str); |
| 41 | + |
| 42 | +/* |
| 43 | + * ISBN reader. |
| 44 | + */ |
| 45 | + |
| 46 | +isbn * |
| 47 | +isbn_in(char *str) |
| 48 | +{ |
| 49 | + isbn *result; |
| 50 | + char *cp; |
| 51 | + int count; |
| 52 | + |
| 53 | + if (strlen(str) != 13) { |
| 54 | + elog(ERROR, "isbn_in: invalid ISBN \"%s\"", str); |
| 55 | + return (NULL); |
| 56 | + } |
| 57 | + if (isbn_sum(str) != 0) { |
| 58 | + elog(ERROR, "isbn_in: purported ISBN \"%s\" failed checksum", |
| 59 | + str); |
| 60 | + return (NULL); |
| 61 | + } |
| 62 | + |
| 63 | + result = (isbn *) palloc(sizeof(isbn)); |
| 64 | + |
| 65 | + strncpy(result->num, str, 13); |
| 66 | + memset(result->pad, ' ', 3); |
| 67 | + return (result); |
| 68 | +} |
| 69 | + |
| 70 | +/* |
| 71 | + * The ISBN checksum is defined as follows: |
| 72 | + * |
| 73 | + * Number the digits from 1 to 9 (call this N). |
| 74 | + * Compute the sum, S, of N * D_N. |
| 75 | + * The check digit, C, is the value which satisfies the equation |
| 76 | + * S + 10*C === 0 (mod 11) |
| 77 | + * The value 10 for C is written as `X'. |
| 78 | + * |
| 79 | + * For our purposes, we want the complete sum including the check |
| 80 | + * digit; if this is zero, then the checksum passed. We also check |
| 81 | + * the syntactic validity if the provided string, and return 12 |
| 82 | + * if any errors are found. |
| 83 | + */ |
| 84 | +int4 |
| 85 | +isbn_sum(char *str) |
| 86 | +{ |
| 87 | + int4 sum = 0, dashes = 0, val; |
| 88 | + int i; |
| 89 | + |
| 90 | + for (i = 0; str[i] && i < 13; i++) { |
| 91 | + switch(str[i]) { |
| 92 | + case '-': |
| 93 | + if (++dashes > 3) |
| 94 | + return 12; |
| 95 | + continue; |
| 96 | + |
| 97 | + case '0': case '1': case '2': case '3': |
| 98 | + case '4': case '5': case '6': case '7': |
| 99 | + case '8': case '9': |
| 100 | + val = str[i] - '0'; |
| 101 | + break; |
| 102 | + |
| 103 | + case 'X': case 'x': |
| 104 | + val = 10; |
| 105 | + break; |
| 106 | + |
| 107 | + default: |
| 108 | + return 12; |
| 109 | + } |
| 110 | + |
| 111 | + sum += val * (i + 1 - dashes); |
| 112 | + } |
| 113 | + return (sum % 11); |
| 114 | +} |
| 115 | + |
| 116 | +/* |
| 117 | + * ISBN output function. |
| 118 | + */ |
| 119 | + |
| 120 | +char * |
| 121 | +isbn_out(isbn * num) |
| 122 | +{ |
| 123 | + char *result; |
| 124 | + |
| 125 | + if (num == NULL) |
| 126 | + return (NULL); |
| 127 | + |
| 128 | + result = (char *) palloc(14); |
| 129 | + |
| 130 | + result[0] = '\0'; |
| 131 | + strncat(result, num->num, 13); |
| 132 | + return (result); |
| 133 | +} |
| 134 | + |
| 135 | +/* |
| 136 | + * Boolean tests for magnitude. |
| 137 | + */ |
| 138 | + |
| 139 | +bool |
| 140 | +isbn_lt(isbn * a1, isbn * a2) |
| 141 | +{ |
| 142 | + return (strncmp(a1->num, a2->num, 13) < 0); |
| 143 | +}; |
| 144 | + |
| 145 | +bool |
| 146 | +isbn_le(isbn * a1, isbn * a2) |
| 147 | +{ |
| 148 | + return (strncmp(a1->num, a2->num, 13) <= 0); |
| 149 | +}; |
| 150 | + |
| 151 | +bool |
| 152 | +isbn_eq(isbn * a1, isbn * a2) |
| 153 | +{ |
| 154 | + return (strncmp(a1->num, a2->num, 13) == 0); |
| 155 | +}; |
| 156 | + |
| 157 | +bool |
| 158 | +isbn_ge(isbn * a1, isbn * a2) |
| 159 | +{ |
| 160 | + return (strncmp(a1->num, a2->num, 13) >= 0); |
| 161 | +}; |
| 162 | + |
| 163 | +bool |
| 164 | +isbn_gt(isbn * a1, isbn * a2) |
| 165 | +{ |
| 166 | + return (strncmp(a1->num, a2->num, 13) > 0); |
| 167 | +}; |
| 168 | + |
| 169 | +bool |
| 170 | +isbn_ne(isbn * a1, isbn * a2) |
| 171 | +{ |
| 172 | + return (strncmp(a1->num, a2->num, 13) != 0); |
| 173 | +}; |
| 174 | + |
| 175 | +/* |
| 176 | + * Comparison function for sorting: |
| 177 | + */ |
| 178 | + |
| 179 | +int4 |
| 180 | +isbn_cmp(isbn * a1, isbn * a2) |
| 181 | +{ |
| 182 | + return (strncmp(a1->num, a2->num, 13)); |
| 183 | +} |
| 184 | + |
| 185 | +/* |
| 186 | + * eof |
| 187 | + */ |
0 commit comments