-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathromanfuncs.c
90 lines (71 loc) · 1.91 KB
/
romanfuncs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
Copyright (C) 2017-2020 Christoph Berg
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "postgres.h"
#include "fmgr.h"
#include "numeral.h"
/* input and output */
extern char *yyerrstr; /* copy of error catched by yyromanerror() */
void yyromanerror (char *s);
void
yyromanerror (char *s)
{
/* store error for later use in number_in */
yyerrstr = pstrdup(s);
}
PG_FUNCTION_INFO_V1(roman_in);
Datum
roman_in (PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
Roman roman;
if (roman_parse(str, &roman) > 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type roman: \"%s\", %s",
str, yyerrstr)));
PG_RETURN_INT64(roman);
}
PG_FUNCTION_INFO_V1(roman_out);
Datum
roman_out(PG_FUNCTION_ARGS)
{
Roman roman = PG_GETARG_INT64(0);
PG_RETURN_CSTRING(roman_cstring(roman));
}
/* format roman numerals */
static char *
romanize (Roman roman)
{
int val[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
char *rom[] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
char res[1000] = "";
int i;
for (i = 0; i < 13; i++) {
while (val[i] <= roman) {
strlcat(res, rom[i], 1000);
roman -= val[i];
}
}
return pstrdup(res);
}
const char *
roman_cstring (Roman roman)
{
if (roman < 0) {
return psprintf("minus %s", roman_cstring(-roman));
} else if (roman == 0) {
return "nulla";
} else if (roman > 10000) {
return psprintf("%lld", roman);
}
return romanize(roman);
}