aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mkfile9
-rw-r--r--readme.md3
-rw-r--r--roman.c90
-rw-r--r--roman.h2
-rw-r--r--test.c44
5 files changed, 148 insertions, 0 deletions
diff --git a/mkfile b/mkfile
new file mode 100644
index 0000000..134694d
--- /dev/null
+++ b/mkfile
@@ -0,0 +1,9 @@
+</$objtype/mkfile
+
+LIB=libroman.a$O
+OFILES=\
+ roman.$O\
+
+HFILES=roman.h
+
+</sys/src/cmd/mklib
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..99724a2
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,3 @@
+# libroman
+
+A library to convert between roman and decimal numbers.
diff --git a/roman.c b/roman.c
new file mode 100644
index 0000000..6606e25
--- /dev/null
+++ b/roman.c
@@ -0,0 +1,90 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include "roman.h"
+
+static int decimal[] = {
+ 1000, 900,
+ 500, 400,
+ 100, 90,
+ 50, 40,
+ 10, 9,
+ 5, 4,
+ 1
+};
+static char *roman[] = {
+ "M", "CM",
+ "D", "CD",
+ "C", "XC",
+ "L", "XL",
+ "X", "IX",
+ "V", "IV",
+ "I"
+};
+static int alpha2roman[] = {
+ /* A, B, C, D, E, F, G, H, I, J, K, L, M */
+ 0, 0, 100, 500, 0, 0, 0, 0, 1, 1, 0, 50, 1000,
+ /* N, O, P, Q, R, S, T, U, V, W, X, Y, Z */
+ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 10, 0, 0
+};
+
+
+static int
+getroman(char c)
+{
+ if(!isalpha(c))
+ return -1;
+ return alpha2roman[toupper(c) - 'A'];
+}
+
+int
+dectoroman(int n, char *buf, ulong len)
+{
+ char *p;
+ int i, o;
+
+ o = 0;
+
+ for(i = 0; i < nelem(decimal); i++){
+ while(n >= decimal[i] && o < len-1){
+ for(p = roman[i]; *p != 0 && o < len-1; )
+ buf[o++] = *p++;
+ n -= decimal[i];
+ }
+ }
+ buf[len-1] = 0;
+ return 0;
+}
+
+int
+romantodec(char *buf)
+{
+ char *ebuf, *larger;
+ int curno, largerno, dec;
+
+ ebuf = strchr(buf, '\0');
+ dec = 0;
+
+ while(buf < ebuf){
+ curno = getroman(*buf);
+ if(curno < 0)
+ return -1;
+ larger = buf;
+ do{
+ largerno = getroman(*larger);
+ if(largerno < 0)
+ return -1;
+ if(largerno > curno)
+ break;
+ }while(*++larger != 0);
+ if(*larger == 0)
+ dec += curno;
+ else{
+ dec += largerno;
+ while(buf < larger)
+ dec -= getroman(*buf++);
+ }
+ buf++;
+ }
+ return dec;
+}
diff --git a/roman.h b/roman.h
new file mode 100644
index 0000000..f105ede
--- /dev/null
+++ b/roman.h
@@ -0,0 +1,2 @@
+int dectoroman(int, char*, ulong);
+int romantodec(char*);
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..fb71a58
--- /dev/null
+++ b/test.c
@@ -0,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+#include "roman.h"
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [ -dr ] number\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int decimal;
+ char *roman, buf[512];
+
+ decimal = -1;
+ roman = nil;
+
+ ARGBEGIN{
+ case 'd':
+ roman = EARGF(usage());
+ break;
+ case 'r':
+ decimal = strtol(EARGF(usage()), nil, 10);
+ break;
+ }ARGEND;
+ if(argc != 0)
+ usage();
+
+ if(decimal >= 0){
+ if(dectoroman(decimal, buf, sizeof buf) < 0)
+ sysfatal("dectoroman: %r");
+ print("%s\n", buf);
+ }else if(roman != nil){
+ if((decimal = romantodec(roman)) < 0)
+ sysfatal("romantodec: %r");
+ print("%d\n", decimal);
+ }else
+ usage();
+
+ exits(nil);
+}