PostgreSQL Source Code: contrib/isn/isn.c Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

16

25

27 .name = "isn",

28 .version = PG_VERSION

29);

30

31#ifdef USE_ASSERT_CHECKING

32#define ISN_DEBUG 1

33#else

34#define ISN_DEBUG 0

35#endif

36

37#define MAXEAN13LEN 18

38

40{

43

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

45

46

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

68static bool

69check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])

70{

71 const char *aux1,

72 *aux2;

80

82 return true;

83

84 while (TABLE[i][0] && TABLE[i][1])

85 {

86 aux1 = TABLE[i][0];

87 aux2 = TABLE[i][1];

88

89

90 if (!isdigit((unsigned char) *aux1) || !isdigit((unsigned char) *aux2))

91 goto invalidtable;

92 a = *aux1 - '0';

93 b = *aux2 - '0';

94

95

96 while (*aux1 && *aux2)

97 {

98 if (!(isdigit((unsigned char) *aux1) &&

99 isdigit((unsigned char) *aux2)) &&

100 (*aux1 != *aux2 || *aux1 != '-'))

101 goto invalidtable;

102 aux1++;

103 aux2++;

104 }

105 if (*aux1 != *aux2)

106 goto invalidtable;

107

108

109 if (a > y)

110 {

111

112 for (j = x; j <= y; j++)

113 {

115 goto invalidindex;

117 goto invalidindex;

118 }

120 x = a;

121 }

122

123

124 y = b;

125 if (y < x)

126 goto invalidtable;

127 i++;

128 }

129

130 return true;

131

132invalidtable:

133 elog(DEBUG1, "invalid table near {\"%s\", \"%s\"} (pos: %d)",

134 TABLE[i][0], TABLE[i][1], i);

135 return false;

136

137invalidindex:

139 return false;

140}

141

142

143

144

145

146static unsigned

148{

149 unsigned ret = 0;

150

151 while (*bufI)

152 {

153 if (isdigit((unsigned char) *bufI))

154 {

155 *bufO++ = *bufI;

156 ret++;

157 }

158 bufI++;

159 }

160 *bufO = '\0';

161 return ret;

162}

163

164

165

166

167

168

169

170

171static unsigned

172hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])

173{

174 unsigned ret = 0;

175 const char *ean_aux1,

176 *ean_aux2,

177 *ean_p;

178 char *firstdig,

179 *aux1,

180 *aux2;

181 unsigned search,

184 step;

185 bool ean_in1,

186 ean_in2;

187

188

189 if (TABLE == NULL || TABLE_index == NULL)

190 {

191 while (*bufI)

192 {

193 *bufO++ = *bufI++;

194 ret++;

195 }

196 *bufO = '\0';

197 return (ret + 1);

198 }

199

200

201

202 search = *bufI - '0';

206

208 if (step == 0)

209 return 0;

210 search = lower + step;

211

212 firstdig = bufI;

213 ean_in1 = ean_in2 = false;

214 ean_aux1 = TABLE[search][0];

215 ean_aux2 = TABLE[search][1];

216 do

217 {

218 if ((ean_in1 || *firstdig >= *ean_aux1) && (ean_in2 || *firstdig <= *ean_aux2))

219 {

220 if (*firstdig > *ean_aux1)

221 ean_in1 = true;

222 if (*firstdig < *ean_aux2)

223 ean_in2 = true;

224 if (ean_in1 && ean_in2)

225 break;

226

227 firstdig++, ean_aux1++, ean_aux2++;

228 if (!(*ean_aux1 && *ean_aux2 && *firstdig))

229 break;

230 if (!isdigit((unsigned char) *ean_aux1))

231 ean_aux1++, ean_aux2++;

232 }

233 else

234 {

235

236

237

238

239 if (*firstdig < *ean_aux1 && !ean_in1)

241 else

243

245 search = lower + step;

246

247

248 firstdig = bufI;

249 ean_in1 = ean_in2 = false;

250 ean_aux1 = TABLE[search][0];

251 ean_aux2 = TABLE[search][1];

252 }

253 } while (step);

254

255 if (step)

256 {

257 aux1 = bufO;

258 aux2 = bufI;

259 ean_p = TABLE[search][0];

260 while (*ean_p && *aux2)

261 {

262 if (*ean_p++ != '-')

263 *aux1++ = *aux2++;

264 else

265 *aux1++ = '-';

266 ret++;

267 }

268 *aux1++ = '-';

269 *aux1 = *aux2;

270 return (ret + 1);

271 }

272 return ret;

273}

274

275

276

277

278

279

280

281static unsigned

283{

284 unsigned weight = 0;

285

286 while (*isn && size > 1)

287 {

288 if (isdigit((unsigned char) *isn))

289 {

290 weight += size-- * (*isn - '0');

291 }

292 isn++;

293 }

294 weight = weight % 11;

295 if (weight != 0)

296 weight = 11 - weight;

297 return weight;

298}

299

300

301

302

303

304

305

306

307static unsigned

309{

310 unsigned check = 0,

311 check3 = 0;

312 unsigned pos = 0;

313

314 if (*num == 'M')

315 {

316 check3 = 3;

317 pos = 1;

318 }

319 while (*num && size > 1)

320 {

321 if (isdigit((unsigned char) *num))

322 {

323 if (pos++ % 2)

324 check3 += *num - '0';

325 else

326 check += *num - '0';

327 size--;

328 }

329 num++;

330 }

331 check = (check + 3 * check3) % 10;

332 if (check != 0)

333 check = 10 - check;

334 return check;

335}

336

337

338

339

340

341

342

343

344static bool

346{

348

350 char *aux;

351 unsigned digval;

352 unsigned search;

354

355 ean >>= 1;

356

358 goto eantoobig;

359

360

361 search = 0;

362 aux = buf + 13;

363 *aux = '\0';

364 do

365 {

366 digval = (unsigned) (ean % 10);

367 ean /= 10;

368 *--aux = (char) (digval + '0');

369 } while (ean && search++ < 12);

370 while (search++ < 12)

371 *--aux = '0';

372

373

374 if (strncmp("978", buf, 3) == 0)

375 {

377 }

378 else if (strncmp("977", buf, 3) == 0)

379 {

381 }

382 else if (strncmp("9790", buf, 4) == 0)

383 {

385 }

386 else if (strncmp("979", buf, 3) == 0)

387 {

389 }

390 else if (*buf == '0')

391 {

393 }

394 else

395 {

397 }

399 goto eanwrongtype;

400

401 *result = ret;

402 return true;

403

404eanwrongtype:

405 if (!errorOK)

406 {

408 {

410 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

411 errmsg("cannot cast EAN13(%s) to %s for number: \"%s\"",

413 }

414 else

415 {

417 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

418 errmsg("cannot cast %s to %s for number: \"%s\"",

420 }

421 }

422 return false;

423

424eantoobig:

425 if (!errorOK)

426 {

427 char eanbuf[64];

428

429

430

431

432

435 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),

436 errmsg("value \"%s\" is out of range for %s type",

438 }

439 return false;

440}

441

442

443

444

445

446static inline void

448{

449 char *aux;

450 unsigned check;

451

452

453

454

455

456

457 if (strncmp("978-", isn, 4) == 0)

458 {

459

460 hyphenate(isn, isn + 4, NULL, NULL);

462 aux = strchr(isn, '\0');

463 while (!isdigit((unsigned char) *--aux));

464 if (check == 10)

465 *aux = 'X';

466 else

467 *aux = check + '0';

468 }

469}

470

471static inline void

473{

474

475

476 hyphenate(isn, isn + 4, NULL, NULL);

477 isn[0] = 'M';

478}

479

480static inline void

482{

483 unsigned check;

484

485

486

487 hyphenate(isn, isn + 4, NULL, NULL);

489 if (check == 10)

490 isn[8] = 'X';

491 else

492 isn[8] = check + '0';

493 isn[9] = '\0';

494}

495

496static inline void

498{

499

500

502 isn[12] = '\0';

503}

504

505

506

507

508

509

510

511

514{

515 ean13 ean = 0;

516

517 while (*num)

518 {

519 if (isdigit((unsigned char) *num))

520 ean = 10 * ean + (*num - '0');

521 num++;

522 }

523 return (ean << 1);

524}

525

526

527

528

529

530

531

532

533

534

535

536static bool

538{

539 const char *(*TABLE)[2];

542

543 char *aux;

544 unsigned digval;

545 unsigned search;

546 char valid = '\0';

547

548

550

551 if ((ean & 1) != 0)

552 valid = '!';

553 ean >>= 1;

554

556 goto eantoobig;

557

558

559 search = 0;

561 *aux = '\0';

562 *--aux = valid;

563

564 do

565 {

566 digval = (unsigned) (ean % 10);

567 ean /= 10;

568 *--aux = (char) (digval + '0');

569 if (search == 0)

570 *--aux = '-';

571 } while (ean && search++ < 13);

572 while (search++ < 13)

573 *--aux = '0';

574

575

577

578

579 if (search == 0)

580 {

581 search = hyphenate(result, result + 3, NULL, NULL);

582 goto okay;

583 }

584

585

586 if (strncmp("978-", result, search) == 0)

587 {

588

592 }

593 else if (strncmp("977-", result, search) == 0)

594 {

595

599 }

600 else if (strncmp("979-0", result, search + 1) == 0)

601 {

602

606 }

607 else if (strncmp("979-", result, search) == 0)

608 {

609

613 }

614 else if (*result == '0')

615 {

616

620 }

621 else

622 {

624 TABLE = NULL;

626 }

627

628

629 digval = search;

630 search = hyphenate(result + digval, result + digval + 2, TABLE, TABLE_index);

631

632

633 if (search == 0)

634 {

635 search = hyphenate(result + digval, result + digval + 2, NULL, NULL);

636 goto okay;

637 }

638

639okay:

640

641 if (shortType)

642 switch (type)

643 {

646 break;

649 break;

652 break;

653 case UPC:

655 break;

656 default:

657 break;

658 }

659 return true;

660

661eantoobig:

662 if (!errorOK)

663 {

664 char eanbuf[64];

665

666

667

668

669

672 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),

673 errmsg("value \"%s\" is out of range for %s type",

675 }

676 return false;

677}

678

679

680

681

682

683

684

685

686

687

688static bool

691{

692 bool digit,

693 last;

694 char buf[17] = " ";

695 char *aux1 = buf + 3;

696

697 const char *aux2 = str;

699 unsigned check = 0,

700 rcheck = (unsigned) -1;

701 unsigned length = 0;

702 bool magic = false,

703 valid = true;

704

705

706 while (*aux2 && length <= 13)

707 {

708 last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0');

709 digit = (isdigit((unsigned char) *aux2) != 0);

710

711 if (*aux2 == '?' && last)

712

713 magic = digit = true;

714 if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))

715 {

716

718 goto eaninvalid;

720 *aux1++ = 'M';

721 length++;

722 }

723 else if (length == 7 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)

724 {

725

727 goto eaninvalid;

729 *aux1++ = toupper((unsigned char) *aux2);

730 length++;

731 }

732 else if (length == 9 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)

733 {

734

736 goto eaninvalid;

738 type = ISBN;

739 *aux1++ = toupper((unsigned char) *aux2);

740 length++;

741 }

742 else if (length == 11 && digit && last)

743 {

744

746 goto eaninvalid;

748 *aux1++ = *aux2;

749 length++;

750 }

751 else if (*aux2 == '-' || *aux2 == ' ')

752 {

753

754 }

755 else if (*aux2 == '!' && *(aux2 + 1) == '\0')

756 {

757

758 if (!magic)

759 valid = false;

760 magic = true;

761 }

762 else if (!digit)

763 {

764 goto eaninvalid;

765 }

766 else

767 {

768 *aux1++ = *aux2;

769 if (++length > 13)

770 goto eantoobig;

771 }

772 aux2++;

773 }

774 *aux1 = '\0';

775

776

777 if (length == 13)

778 {

779

781 goto eaninvalid;

783 check = buf[15] - '0';

784 }

785 else if (length == 12)

786 {

787

789 goto eaninvalid;

790 check = buf[14] - '0';

791 }

792 else if (length == 10)

793 {

795 goto eaninvalid;

796 if (buf[12] == 'X')

797 check = 10;

798 else

799 check = buf[12] - '0';

800 }

801 else if (length == 8)

802 {

804 goto eaninvalid;

806 if (buf[10] == 'X')

807 check = 10;

808 else

809 check = buf[10] - '0';

810 }

811 else

812 goto eaninvalid;

813

815 goto eaninvalid;

816

817

819 goto eanwrongtype;

821 goto eanwrongtype;

822 switch (type)

823 {

825 valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));

826

827 if (buf[3] == '0')

829 else if (strncmp("977", buf + 3, 3) == 0)

831 else if (strncmp("978", buf + 3, 3) == 0)

833 else if (strncmp("9790", buf + 3, 4) == 0)

835 else if (strncmp("979", buf + 3, 3) == 0)

838 goto eanwrongtype;

839 break;

841 memcpy(buf, "9790", 4);

842

843 valid = (valid && ((rcheck = checkdig(buf, 13)) == check || magic));

844 break;

846 memcpy(buf, "978", 3);

847 valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));

848 break;

850 memcpy(buf + 10, "00", 2);

851

852 memcpy(buf, "977", 3);

853 valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));

854 break;

855 case UPC:

856 buf[2] = '0';

857 valid = (valid && ((rcheck = checkdig(buf + 2, 13)) == check || magic));

858 default:

859 break;

860 }

861

862

863 for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);

864 aux1[12] = checkdig(aux1, 13) + '0';

865 aux1[13] = '\0';

866

867 if (!valid && !magic)

868 goto eanbadcheck;

869

871 *result |= valid ? 0 : 1;

872 return true;

873

874eanbadcheck:

876 {

877

879 *result |= 1;

880 return true;

881 }

882

883 if (rcheck == (unsigned) -1)

884 {

885 ereturn(escontext, false,

886 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

887 errmsg("invalid %s number: \"%s\"",

889 }

890 else

891 {

892 ereturn(escontext, false,

893 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

894 errmsg("invalid check digit for %s number: \"%s\", should be %c",

896 }

897

898eaninvalid:

899 ereturn(escontext, false,

900 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

901 errmsg("invalid input syntax for %s number: \"%s\"",

903

904eanwrongtype:

905 ereturn(escontext, false,

906 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),

907 errmsg("cannot cast %s to %s for number: \"%s\"",

909

910eantoobig:

911 ereturn(escontext, false,

912 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),

913 errmsg("value \"%s\" is out of range for %s type",

915}

916

917

918

919

920

921void

923{

925 {

927 elog(ERROR, "EAN13 failed check");

929 elog(ERROR, "ISBN failed check");

931 elog(ERROR, "ISMN failed check");

933 elog(ERROR, "ISSN failed check");

936 }

937

938

940 "Accept input with invalid ISN check digits.",

941 NULL,

943 false,

945 0,

946 NULL,

947 NULL,

948 NULL);

949

951}

952

953

954

958{

960 char *result;

962

964

967}

968

969

970

974{

976 char *result;

978

980

983}

984

985

986

990{

993

997}

998

999

1000

1004{

1007

1011}

1012

1013

1014

1018{

1021

1025}

1026

1027

1028

1032{

1035

1039}

1040

1041

1042

1046{

1049

1053}

1054

1055

1056

1060{

1063

1065

1067}

1068

1072{

1075

1077

1079}

1080

1084{

1087

1089

1091}

1092

1096{

1099

1101

1103}

1104

1105

1106

1107

1111{

1113

1115}

1116

1117

1118

1122{

1124

1127}

1128

1129

1130

1131

1135{

1137

1142}

1143

1147{

1149}

static const unsigned EAN13_index[10][2]

static const char * EAN13_range[][2]

static const char * ISBN_range[][2]

static const unsigned ISBN_index[10][2]

static const unsigned ISBN_index_new[10][2]

static const char * ISBN_range_new[][2]

static const char * ISMN_range[][2]

static const unsigned ISMN_index[10][2]

static const unsigned ISSN_index[10][2]

static const char * ISSN_range[][2]

static const unsigned UPC_index[10][2]

static const char * UPC_range[][2]

int errcode(int sqlerrcode)

int errmsg(const char *fmt,...)

#define ereturn(context, dummy_value,...)

#define ereport(elevel,...)

#define PG_RETURN_CSTRING(x)

#define PG_GETARG_CSTRING(n)

#define PG_GETARG_BOOL(n)

#define PG_RETURN_BOOL(x)

void DefineCustomBoolVariable(const char *name, const char *short_desc, const char *long_desc, bool *valueAddr, bool bootValue, GucContext context, int flags, GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook)

void MarkGUCPrefixReserved(const char *className)

int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)

Datum upc_cast_from_ean13(PG_FUNCTION_ARGS)

Datum ean13_out(PG_FUNCTION_ARGS)

Datum issn_in(PG_FUNCTION_ARGS)

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

Datum isn_out(PG_FUNCTION_ARGS)

static bool string2ean(const char *str, struct Node *escontext, ean13 *result, enum isn_type accept)

Datum make_valid(PG_FUNCTION_ARGS)

static void ean2ISBN(char *isn)

Datum ismn_in(PG_FUNCTION_ARGS)

Datum accept_weak_input(PG_FUNCTION_ARGS)

static bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType)

const unsigned TABLE_index[10][2]

Datum weak_input_status(PG_FUNCTION_ARGS)

Datum upc_in(PG_FUNCTION_ARGS)

static bool ean2isn(ean13 ean, bool errorOK, ean13 *result, enum isn_type accept)

static const char *const isn_names[]

Datum isbn_in(PG_FUNCTION_ARGS)

Datum issn_cast_from_ean13(PG_FUNCTION_ARGS)

static void ean2UPC(char *isn)

Datum ean13_in(PG_FUNCTION_ARGS)

Datum ismn_cast_from_ean13(PG_FUNCTION_ARGS)

Datum isbn_cast_from_ean13(PG_FUNCTION_ARGS)

static unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2])

static unsigned checkdig(char *num, unsigned size)

static void ean2ISMN(char *isn)

Datum is_valid(PG_FUNCTION_ARGS)

PG_FUNCTION_INFO_V1(isn_out)

static unsigned dehyphenate(char *bufO, char *bufI)

static unsigned weight_checkdig(char *isn, unsigned size)

static ean13 str2ean(const char *num)

pg_attribute_unused() static bool check_table(const char *(*TABLE)[2]

static void ean2ISSN(char *isn)

#define PG_GETARG_EAN13(n)

#define PG_RETURN_EAN13(x)

char * pstrdup(const char *in)

Datum lower(PG_FUNCTION_ARGS)

Datum upper(PG_FUNCTION_ARGS)

#define accept(s, addr, addrlen)